【问题标题】:const_cast const STL container, is it undefined behavior?const_cast const STL 容器,是未定义的行为吗?
【发布时间】:2016-01-26 12:37:17
【问题描述】:

我知道 const_cast 的使用不会引入未定义的行为(即,它可以安全使用),只要您的变量 const_casting 最初没有定义为 const 或者如果它最初被定义为const,您不会通过其const_casted 别名对其进行修改。

然而,众所周知,大多数 STL 容器(例如,std::vectorstd::set)动态分配其内部缓冲区。基于这一事实,我认为将const 定义的std::vector 放在只读内存中是不可能的。

当然,如果上述情况成立,我会假设这种 STL 容器即使它们被定义为 const,例如:

std::vector<int> const v;

const_cast他们并通过他们的const_casted 别名更改他们是合法的,不会导致任何未定义的行为。

上述假设成立还是我错了?

【问题讨论】:

  • 如果标准说是UB,那就是UB。优化器使用它来做各种疯狂的事情,假设 const 对象不会被修改。
  • 注意,在常量向量的情况下,编译器不需要动态分配内存(避免分配标准子句),事实上,可以放置常量向量完全在静态只读内存中。
  • @101010 我认为您选择我的答案为“解决方案”有点太快了。它还不是(在我写这篇文章的时候)你的问题的真正答案。到目前为止,我刚刚解决了动态分配的内存必须是可变的假设。
  • 如果你想要一个对象是可修改的,不要说它不是。

标签: c++ c++11 stl undefined-behavior const-cast


【解决方案1】:

C++ 标准明确指出,为通过new const T 创建的对象丢弃const 并对其进行修改是未定义行为。

例如,C++11 标准在其 §7.1.6.1/4 中包含此示例:

const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object

标准中的示例是非规范性的,只是示例,并且可能是错误的。例如,在 C++03 中,几乎所有使用 &lt;iostream&gt; 的示例都是错误的(当时正式有必要还包括 &lt;ostream&gt;,但这不是委员会的意图),以及 C 中的表达式示例++03 §5/4 是错误的,称行为未指定而不是未定义(这可能反映了最初的意图)。但是,上面的例子是正确的。

这表明动态分配的内存不需要是可变的:修改它可以有未定义的行为。

但是,例如,当创建了一个std::string,它的缓冲区分配(如果有)发生在构造函数的执行期间,此时对象还不是const,并且缓冲区没有分配为const。因此,如果分配了缓冲区,则该缓冲区最初不是const。但是对于这个特定的例子,std::string 可以使用小缓冲区优化,它直接在对象中使用存储,然后最初是const(可能分配在只读内存中)。这就涉及到no原来const对象可以修改的规则了。


除了只读内存场景之外,UB 的基本原理还包括它可以为编译器提供优化的可能性。

正如juanchopanzaa comment to the question 中的注释,

优化器使用它来做各种疯狂的事情,假设const 对象不会被修改。

通过修改最初的 const 对象来打破优化器的假设,可能会产生灾难性且实际上无法预测的后果。

【讨论】:

    猜你喜欢
    • 2011-08-23
    • 2021-11-15
    • 1970-01-01
    • 2011-11-13
    • 2011-05-16
    • 1970-01-01
    • 2011-04-13
    相关资源
    最近更新 更多