const_cast类构造函数中的const成员

时间:2013-04-18 17:40:58

标签: 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);
  }
};

我曾经假设在构造函数中执行此操作基本上没问题,因为此时没有其他人依赖它,所以它不会与优化等交互不良。

然而,最近有人告诉我这是“未定义的行为”,并且在任何情况下构建const对象之后改变const对象基本上是非法的。

有人可以澄清吗?这是一个糟糕/未定义的行为/事情吗?

2 个答案:

答案 0 :(得分:5)

这是未定义的行为。根据C ++ 11标准的第7.1.6.1/4段:

  

除了可以修改声明mutable(7.1.1)的任何类成员之外,任何修改const的尝试都是如此   对象在其生命周期(3.8)中导致未定义的行为。

在这种情况下,您似乎希望您的对象在构造后“变得”不变。这是不可能的。

如果您的vectorconst,则应在构造函数initialization list中对其进行初始化:

qqq(vector<foo>& other) 
    : my_foo(std::move(other)) 
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}

注意,除非你有充分的理由通过指针传递 - 在这种情况下,你还应该检查指针是否为非空 - 你应该考虑通过引用传递(如上所示),这是常见的实践。

<强>更新

正如Pete Becker在评论中正确指出的那样,正确的设计会表明从vector参数移出的决定应属于qqq调用者构造函数,而不是构造函数本身。

如果构造函数总是应该从它的参数移开,那么你可以让它接受一个右值引用,明确构造函数本身对调用者的期望:

qqq(vector<foo>&& other) 
//             ^^
    : my_foo(std::move(other)) 
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}

这样,调用者必须在qqq的构造函数的输入中提供 rvalue

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

答案 1 :(得分:2)

是的,它确实是UB(未定义的行为)。初始化后,您无法修改const对象。你应该做的是使用成员初始化列表,可能还有一个函数:

struct qqq {
  const vector<foo> my_foo;

  qqq(vector<foo> *other) : my_foo(initialiseFoo(*other)) {}

  static vector<foo> initialiseFoo(vector<foo> &other) {
    vector<foo> tmp;
    other.swap(tmp);
    return tmp;
  }
};

一个体面的优化者应该能够摆脱暂时的。

如果你可以使用C ++ 11,它实际上更简单:

struct qqq {
  const vector<foo> my_foo;

  qqq(vector<foo> *other) : my_foo(std::move(*other))
  {
    other->clear();  //Just in case the implementation of moving vectors is really weird
  }
};