未实现赋值运算符时构造函数被调用的C++编译器行为解析
关于你遇到的String类赋值行为的底层解释
兄弟,你这个问题其实是C++里隐式类型转换和临时对象在偷偷搞事情!我来给你拆解清楚编译器到底做了什么,以及为啥会出现你看到的现象:
1. 为啥String s; s="Hello World";没报错,还调用了String(const char* _pc)构造函数?
首先,你没给String类重载任何赋值运算符(比如String& operator=(const char*)或者拷贝赋值运算符),但C++编译器会帮你自动生成一个默认的拷贝赋值运算符,签名是String& operator=(const String&)。
当你执行s="Hello World"时,编译器发现右边是const char*类型,和左边的String类型不匹配,它会尝试做隐式类型转换:
- 用
"Hello World"这个const char*作为参数,调用你实现的String(const char* _pc)构造函数,创建一个临时的String对象; - 然后调用编译器自动生成的默认拷贝赋值运算符,把这个临时对象的成员变量(
capacity和start)浅拷贝给s; - 因为这次操作没触发内存重复释放或者野指针这类明显错误(但其实你的代码有浅拷贝隐患,只是这次刚好没炸),所以程序没报错。
2. 为啥析构函数被调用了两次?
这完全是那个临时对象的锅:
- 第一次析构:赋值操作完成后,那个临时创建的
String对象就失去了作用,编译器会自动销毁它,调用一次析构函数; - 第二次析构:
main函数执行完毕,局部对象s的作用域结束,程序会调用它的析构函数,这就是第二次调用。
顺便提个你的代码小问题
你的析构函数里的逻辑有问题:
if (capacity == 1) delete start; if (capacity > 1) delete[] start;
不管capacity是1还是更大,你在构造函数里都是用new char[]分配的内存,所以必须统一用delete[]释放,哪怕数组大小是1。用delete去释放new[]分配的内存属于未定义行为,运气好没事,运气差直接崩。
内容的提问来源于stack exchange,提问作者Harsh Patel
相关产品推荐
相关产品推荐

