破坏不存在的对象

时间:2017-11-26 18:31:55

标签: c++ c++11 destructor move move-semantics

我在移动语义方面有点挣扎。我读了很多关于这个话题的内容,然而,有两个具体的问题,我没有找到任何答案,因此,喜欢把它们呈现给你。

首先,我有以下示例代码:

#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; ....?

提前致谢!

干杯

1 个答案:

答案 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是你真正的朋友。