我在移动语义方面有点挣扎。我读了很多关于这个话题的内容,然而,有两个具体的问题,我没有找到任何答案,因此,喜欢把它们呈现给你。
首先,我有以下示例代码:
#include <iostream>
#include <cstddef>
class A
{
public:
A *ptr;
virtual ~A()
{
std::cout << "dtor" << std::endl;
delete ptr;
ptr=nullptr;
}
};
main()
{
A x, y;
x.ptr = &y;
}
// compile and link like this with g++: g++ -std=c++0x -lstdc++ code.cc
A类能够拥有自己的成员。我使用这个&#34;复合模式&#34;构建层次结构的概念。但是,在这种情况下,当对象x被破坏时,它的析构函数会删除指向对象y的指针。当最终对象y应该被破坏时,它已经产生错误......我该如何解决这个问题?
第二种情况如下:
main()
{
A x, y;
y = std::move(x);
std::cout << "x.ptr: " << x.ptr << std::endl;
std::cout << "y.ptr: " << y.ptr << std::endl;
}
在这里,我可以看到两个引用都是相同的,这意味着它们都存在。我虽然std :: move将内容从x移动到y。我原以为x.ptr是&#34;空&#34; ....?
提前致谢!
干杯
答案 0 :(得分:2)
在第一种情况下,你的x和y对象都是在堆栈上创建的,因此它们将被自动销毁。但是,您的类A的析构函数使用delete
,它假定ptr引用的对象是使用new在堆上创建的。
因此,将x.ptr设置为引用在堆栈上创建的对象(如y)是错误的。正确的代码是
x.ptr = new A;
这是原始指针的危险 - 你无法区分指向动态分配对象(最终必须delete
)和“只是指针”(你不能)的指针。
最好使用std::unique_ptr<A>
而不是原始指针A*
。
它也会调用删除我自己,因此不需要delete ptr
。
至于第二种情况,对于原始类型,移动实际上只是一个副本。如果你从int移动到int,或者从ptr移动到ptr,它只是一个副本,因为没有什么可以优化移动原始类型,移动对象没有特殊的“清空”。但对于你的情况,有一些称为智能指针的好东西实际上是“清空”(因为它保证了正确性)。你猜对了 - 我在谈论std::unique_ptr
。
再次,如果你将你的ptr从A*
更改为std::unique_ptr<A>
,那么移动将完成你正在寻找的工作。
用两个词来说,std::unique_ptr
是你真正的朋友。