drw*_*owe 4 c++ constructor const
当我希望类的成员变量在类的生命期间保持不变时,我有时会使用const_cast,但它在构造函数中需要是可变的.例:
struct qqq {
const vector<foo> my_foo;
qqq(vector<foo>* other) {
vector<foo>& mutable_foo = const_cast<vector<foo>&>(my_foo)
other->swap(mutable_foo);
}
};
Run Code Online (Sandbox Code Playgroud)
我曾经假设在构造函数中执行此操作基本上没问题,因为此时没有其他人依赖它,因此它不会与优化等交互不良.
然而,最近有人告诉我这是"未定义的行为",并且在任何情况下构造const对象之后改变const对象基本上是非法的.
有人可以澄清吗?这是一个不好/未定义的行为/事情吗?
这是未定义的行为.根据C++ 11标准的第7.1.6.1/4段:
除了
mutable可以修改声明的任何类成员(7.1.1)之外,任何const在其生命周期内修改对象的尝试(3.8)都会导致未定义的行为.
在这种情况下,您似乎希望您的对象在构造后"变得"不变.这是不可能的.
如果你vector的意思是const,你应该在构造函数的初始化列表中初始化它:
qqq(vector<foo>& other)
: my_foo(std::move(other))
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}
Run Code Online (Sandbox Code Playgroud)
请注意,除非你有充分的理由通过指针传递 - 在这种情况下,你还应该检查指针是否为非空 - 你应该考虑通过引用传递(如上所示),这是常见的做法.
更新:
皮特正确贝克尔在评论中指出,正确的设计建议,决定从移动vector参数应该属于调用者的qqq的构造函数,而不是在构造函数本身.
如果构造函数总是应该从它的参数移开,那么你可以让它接受一个右值引用,清楚地表明构造函数本身对调用者的期望是什么:
qqq(vector<foo>&& other)
// ^^
: my_foo(std::move(other))
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}
Run Code Online (Sandbox Code Playgroud)
这样,调用者必须在输入的构造函数中提供rvalueqqq:
std::vector<foo> v;
// ...
qqq q1(v); // ERROR!
qqq q2(std::move(v)); // OK! Now the client is aware that v must be moved from
Run Code Online (Sandbox Code Playgroud)