Joe*_*elä 2 c++ constants c++20
我有一个Obj带有 const 成员的课程i:
class Obj {
const int i;
...
};
Run Code Online (Sandbox Code Playgroud)
但我需要在移动构造函数中将 i 设置为 0。(因为如果i不是0,析构函数将删除东西,并且由于我移动了对象,这将导致双重释放)
Obj::i像这样在移动构造函数中进行修改是否安全?
Obj::Obj(Obj &&other) :
i(other.i)
{
std::destroy_at(&other.i);
std::construct_at(&other.i, 0);
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,当std::construct_at用“透明可替换对象”替换 other.i 时,这样做是安全的。但我不完全确定这个定义的含义:
(8) 对象 o1 可以透明地被对象 o2 替换,如果:
(8.1) o2 占用的存储空间恰好覆盖了 o1 占用的存储空间,并且
(8.2) o1 和 o2 是同一类型(忽略顶级 cv 限定符),并且
(8.3) o1 不是一个完整的 const 对象,并且
(8.4) o1 和 o2 都不是潜在重叠的子对象 ([intro.object]),并且
(8.5) o1 和 o2 都是完整的对象,或者 o1 和 o2 分别是对象 p1 和 p2 的直接子对象,并且 p1 显然可以被 p2 替换。
(https://eel.is/c++draft/basic#life-8)
据我了解,至少8.1、8.2和8.3适用,但我不完全确定,而且我不太理解8.4和8.5。
那么我认为这应该有效(在 C++20 中)是否正确,或者这会导致未定义的行为?
潜在重叠的子对象是基类子对象或标有 的成员[[no_unique_address]]。Obj::i并非如此 8.4 适用。
如果您将 p1 和 p2 视为同一个对象,other,则 8.5 可能适用(对象可以透明地替换自身),除非它不递归应用(例如,是某个其他类的Obj基类/成员,或者[[no_unique_address]]它所属的完整对象是const并且other曾经是const_cast或现在是可变成员)。但它实际上总是适用的。
但请考虑不将其设为const成员,因为您确实需要在此处对其进行修改。您的移动构造函数也应该清除other(例如,设置任何指针nullptr,清除任何文件句柄,将其他内容清零),这样析构函数就不会意外地重复删除内容。