我有点困惑,因为我确信这应该有所不同。看一下这段代码示例:
#include <iostream>
#include <string>
using namespace std;
class base
{
public:
virtual ~base() = default;
};
class derived : public base
{
private:
int a = 0;
int *b = nullptr;
std::string lol;
public:
derived(std::string s) : b(new int(6)), lol{s} { cout << "ctor " << lol << endl; }
derived(derived const& d) : lol{d.lol + " copy"} {cout << "copy " << lol << endl; }
virtual ~derived() { cout << "dtor " << lol << endl; delete b; }
virtual void superFunction() { cout << "OMG " << lol << endl; }
};
int main()
{
derived a("a");
derived b("b");
a = b;
}
关闭所有优化的程序输出是:
ctor a
ctor b
dtor b
dtor b
我确信在这种情况下编译器应该生成删除对象a
的代码并使用复制构造函数来创建新对象。相反,它使用隐式声明的operator=
。
有人可以解释原因吗?或者指向C ++标准。
感谢。
答案 0 :(得分:5)
编写a = b;
时,编译器会调用赋值运算符,如果代码中不存在则会自动生成赋值运算符,并且不会标记为已删除。只有当您尝试从另一个对象初始化一个新对象时才使用复制构造函数:
derived a("a");
derived b = a;
此外,您的代码在主要返回之前崩溃,因为它尝试删除b
,a
指向同一内存,b
默认分配后指向a = b;
如果要在a
执行后删除derived
a = b;
析构函数,您只需要复制和交换习惯用法。 What is the copy and swap idiom?在遗留和现代C ++中如何做到这一点有一个很好的答案。从该答案中正确实施四法则将完全符合DRY原则并帮助您避免内存问题。注意通过值将参数传递给operator=
的神话般的技巧,这使得编译器选择适当的构造函数(复制或移动)并允许您只编写四个方法而不是所有{{3}他们。