【问题标题】:Placement new vs assignment in STL implementation在 STL 实现中放置新与分配
【发布时间】:2016-02-01 21:09:58
【问题描述】:

我一直在好奇地检查 STL 的实现,并在 experimental/optional 中找到了这段代码。代码如下:

optional&
operator=(const optional& __opt)
{
    if (this->__engaged_ == __opt.__engaged_)
    {
        if (this->__engaged_)
            this->__val_ = __opt.__val_;
    }
    else
    {
        if (this->__engaged_)
            this->__val_.~value_type();
        else
            ::new(_VSTD::addressof(this->__val_)) value_type(__opt.__val_);
        this->__engaged_ = __opt.__engaged_;
    }
    return *this;
}

这是std::optional<T> 类的复制赋值运算符实现。我认为为了讨论的效果,弄清楚这些变量是什么也应该很重要,所以这里是类的存储:

typedef _Tp value_type;
union
{
    char __null_state_;
    value_type __val_;
};
bool __engaged_ = false;

第一个代码摘录以两种不同的方式显示了对 __val_ 的赋值,一种使用简单赋值 (this->__val_ = __opt.__val_),另一种使用放置新 (::new(_VSTD::addressof(this->__val_)) value_type(__opt.__val_);)。有什么不同?在这种情况下,为什么要使用一个或另一个?

【问题讨论】:

    标签: c++ new-operator placement-new


    【解决方案1】:

    默认情况下,可选项中的存储未初始化。在第一种情况下,存储已经构建,因此它使用对象的复制赋值运算符。

    在第二种情况下,它需要在分配的存储中构造一个对象,因为在该代码路径中,赋值的左侧从未构造过它的存储..

    【讨论】:

    • 重要的是__val_的赋值运算符会假设前面的内容是有效的。如果存储空间被保留但从未分配,则无法满足此先决条件,您需要做一些更复杂的事情。
    • 是的@MarkRansom 我知道了 ;) 在意识到它变得非常明显之后,我错过了内存尚未初始化的事实 :)
    【解决方案2】:

    这或多或少是唯一的方法。当 rhs (__opt) 没有被 'engaged' 时,需要销毁 __val__,如果它被占用,而我们的成员没有,我们必须在那里创建一个对象。

    第一个if 处理两个参数都“参与”或不“参与”的情况,在这种情况下,要么什么都不做,要么我们可以使用简单的赋值。

    【讨论】:

      猜你喜欢
      • 2011-07-15
      • 1970-01-01
      • 2014-10-30
      • 1970-01-01
      • 1970-01-01
      • 2017-10-29
      • 2021-05-02
      • 2011-01-08
      相关资源
      最近更新 更多