我写了下面的代码:
#define LOG cout << __PRETTY_FUNCTION__ << endl;
class MyClass
{
private:
int* ptr;
public:
MyClass()
: ptr(new int(10))
{
LOG
}
~MyClass()
{
LOG
if (ptr)
{
delete ptr;
ptr = nullptr;
}
}
MyClass(const MyClass& a)
: ptr(nullptr)
{
LOG
ptr = new int;
*ptr = *(a.ptr);
}
MyClass& operator=(const MyClass& a)
{
LOG
if (this == &a)
{
return *this;
}
delete ptr;
ptr = new int;
*ptr = *(a.ptr);
return *this;
}
MyClass(MyClass&& a)
: ptr(nullptr)
{
LOG
ptr = a.ptr;
a.ptr = nullptr;
}
MyClass& operator=(MyClass&& a)
{
LOG
if (this == &a)
{
return *this;
}
delete ptr;
ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
void printClass()
{
LOG;
}
};
MyClass function()
{
MyClass m;
return m;
}
int main()
{
MyClass m = function();
return 0;
}
程序输出:
MyClass::MyClass()
MyClass::~MyClass()
这不会调用move构造函数。有什么问题吗?
我期待以下输出:
MyClass::MyClass()
MyClass::MyClass(MyClass&&)
MyClass::~MyClass()
MyClass::MyClass(MyClass&&)
MyClass::~MyClass()
MyClass::~MyClass()
看起来编译器正在做一些优化。如果是这种情况,那为什么我们需要移动构造函数或移动赋值运算符。
答案 0 :(得分:2)
这不会调用move构造函数。有什么问题吗?
不,没有错。
看起来编译器正在做一些优化。
这正是编译器所做的。
如果是这种情况,那么为什么我们需要为该情况移动构造函数或赋值运算符。
您的类需要自定义的move构造函数和赋值运算符,因为隐式生成的类将无法正确处理分配的资源。
仅仅因为编译器可能乐观,并不是将它们排除在外的好理由。尤其是因为在其他程序中,根本无法优化移动。
PS。
析构函数中的 if (ptr)
是多余的。删除nullptr很好。您也不必在operator=
中进行检查,这很好。
deleteMe
是危险功能。在一些非常晦涩的情况下,删除自我可能很有用,但是您的班级对此没有任何要求。在非动态实例上调用此函数的行为是不确定的。
在移动复制副本构造函数中将ptr
初始化为null是多余的,因为您无条件地在构造函数的主体中覆盖了该值。