被移动的对象需要被销毁吗?

10
如果我使用move构造函数b中构造a,那么是否仍然需要析构b,或者可以不进行析构呢?
在实现一个optional<T>模板时,我想到了这个问题。摘录如下:
~optional()
{
    if (initialized)
    {
        reinterpret_cast<T*>(data)->~T();
    }
}

optional(optional&& o) : initialized(o.initialized)
{
    if (initialized)
    {
        new(data) T(std::move(*o));   // move from o.data
        o.initialized = false;        // o.data won't be destructed anymore!
    }
}

当然,我可以用一个三值枚举来替换布尔类型的initialized,以区分已初始化、未初始化和移动状态。但我只是想知道这是否绝对必要。

为什么要使用析构函数?为什么不使用delete?移动后,您可以将其设置为0。 - balki
2
@balki:不确定你的意思。我的optional<T>模板中没有动态内存,所以没有需要delete的东西。 - fredoverflow
1
我正在实现完全相同的东西,并且有完全相同的问题!谢谢! - VF1
3个回答

14

是的,仍然需要析构b。从移动的对象是一个有效的、已构造的对象。在某些情况下,它甚至可能持有仍需处理的资源。在像您展示的通用代码中,T甚至可能没有移动构造函数。在这种情况下,您可能会调用复制构造函数。因此,您绝不能假设~T()是无操作并且可以省略。


2
+1,我没有注意到可能会调用复制构造函数的部分。 - Puppy

3
是的,你仍然需要销毁它们。其中一个设计可以显示这个缺陷,例如基于观察者模式的设计,其中一个对象保持指向另一个对象的指针列表。不运行析构函数将不会删除指针,并且当它试图访问不存在的对象时,代码将崩溃。
在你的例子中更容易的方法是只是不在被移动的对象中将initialized设置为false。该值在从已移动的对象中获取后仍定义为处于有效状态,并且所引用的rvalue的析构函数将在不需要进一步干预的情况下清理它。

2

我希望回答你的问题是否定的,但我不确定这是否是正确的问题。请考虑以下内容:

{  // start of scope
    T maybe_moved;
    if(some_condition) {
        T(std::move(maybe_moved));
    }
// end of scope
}

T::~T()显然只应该针对maybe_moved对象调用一次。如果移动构造函数调用它,你如何使这种无害的代码工作呢?


我的移动构造函数没有调用任何析构函数...? - fredoverflow
@FredOverflow 假定你在问题中提到的任何假设机制都适用于销毁已移动对象。 - Luc Danton
@Barry OP的问题涉及用户定义的特殊成员,而不是语言的规定方式。正如我在我的答案中所提到的,移动构造函数如何执行此任务(即在这种情况下从if语句内部执行)。 - Luc Danton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接