在 STL 实现中放置新的 vs 赋值
Placement new vs assignment in STL implementation
我一直好奇地检查 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>
class 的复制赋值运算符实现。我相信为了讨论的效果,弄清楚这些变量是什么也很重要,所以这里是 classe 的存储:
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_);
)。有什么不同?在这种情况下,为什么要使用一个或另一个?
默认情况下不初始化可选中的存储。在第一种情况下,存储已经构建,因此它使用对象的复制赋值运算符。
在第二种情况下,它需要将一个对象构造到分配的存储空间中,因为在该代码路径中,赋值的左侧从未构造过它的存储空间..
这或多或少是唯一的方法。当rhs(__opt
)不是'engaged'时,需要去析构__val__
,如果是engaged,而我们的member不是,我们就得在那里创建一个对象。
第一个 if
处理两个参数都是 'engaged' 或不是 'engaged' 的情况,在这种情况下,要么什么都不做,要么我们可以使用简单的赋值.
我一直好奇地检查 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>
class 的复制赋值运算符实现。我相信为了讨论的效果,弄清楚这些变量是什么也很重要,所以这里是 classe 的存储:
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_);
)。有什么不同?在这种情况下,为什么要使用一个或另一个?
默认情况下不初始化可选中的存储。在第一种情况下,存储已经构建,因此它使用对象的复制赋值运算符。
在第二种情况下,它需要将一个对象构造到分配的存储空间中,因为在该代码路径中,赋值的左侧从未构造过它的存储空间..
这或多或少是唯一的方法。当rhs(__opt
)不是'engaged'时,需要去析构__val__
,如果是engaged,而我们的member不是,我们就得在那里创建一个对象。
第一个 if
处理两个参数都是 'engaged' 或不是 'engaged' 的情况,在这种情况下,要么什么都不做,要么我们可以使用简单的赋值.