const_cast const STL 容器,是否为未定义行为?
const_cast const STL container, is it undefined behavior?
我知道使用 const_cast
不会引入未定义的行为(即,使用它是安全的),只要您 const_cast
ing 的变量最初没有被定义为const
或者如果它最初被定义为 const
,则您不会通过其 const_cast
ed 别名修改它。
然而,众所周知,大多数 STL 容器(例如,std::vector
、std::set
)会动态分配其内部缓冲区。基于这个事实,我认为将 const
定义的 std::vector
放在只读存储器中是不可能的。
当然,如果上述成立,我会假设这种 STL 容器,即使它们被定义为 const
,例如:
std::vector<int> const v;
const_cast
通过他们的 const_cast
ed 别名修改它们是合法的,不会导致任何未定义的行为。
以上假设成立还是我错了?
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
标准中的例子是non-normative,只是例子,可能是错误的。例如,在 C++03 中,几乎所有使用 <iostream>
的示例都是错误的(当时正式需要也包括 <ostream>
,但这不是委员会的意图),并且C++03 §5/4 中的表达式示例是错误的,表示行为未指定而不是未定义(这可能反映了初衷)。但是,上面的例子是正确的。
这表明动态分配的内存不需要是可变的:修改它可以有未定义的行为。
但是,例如a std::string
被创建,其缓冲区(如果有的话)的分配发生在构造函数的执行期间,此时对象尚未 const
,并且缓冲区未分配为 const
.所以缓冲区,如果分配了一个,原来不是const
。但是对于这个特定的例子,std::string
可能会使用小缓冲区优化,它直接在对象中使用存储,然后最初是 const
(可能分配在只读内存中)。这符合 no 最初 const
对象可以修改的规则。
除了 read-only 内存场景之外,UB 的基本原理还包括它可以为编译器提供优化的可能性。
如juanchopanza notes in ,
” Optimizers use this to do all kind of crazy stuff that assumes const
objects won't be modified.
通过修改最初的 const
对象来打破优化器的假设,可能会造成灾难性的且实际上无法预测的后果。
我知道使用 const_cast
不会引入未定义的行为(即,使用它是安全的),只要您 const_cast
ing 的变量最初没有被定义为const
或者如果它最初被定义为 const
,则您不会通过其 const_cast
ed 别名修改它。
然而,众所周知,大多数 STL 容器(例如,std::vector
、std::set
)会动态分配其内部缓冲区。基于这个事实,我认为将 const
定义的 std::vector
放在只读存储器中是不可能的。
当然,如果上述成立,我会假设这种 STL 容器,即使它们被定义为 const
,例如:
std::vector<int> const v;
const_cast
通过他们的 const_cast
ed 别名修改它们是合法的,不会导致任何未定义的行为。
以上假设成立还是我错了?
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
标准中的例子是non-normative,只是例子,可能是错误的。例如,在 C++03 中,几乎所有使用 <iostream>
的示例都是错误的(当时正式需要也包括 <ostream>
,但这不是委员会的意图),并且C++03 §5/4 中的表达式示例是错误的,表示行为未指定而不是未定义(这可能反映了初衷)。但是,上面的例子是正确的。
这表明动态分配的内存不需要是可变的:修改它可以有未定义的行为。
但是,例如a std::string
被创建,其缓冲区(如果有的话)的分配发生在构造函数的执行期间,此时对象尚未 const
,并且缓冲区未分配为 const
.所以缓冲区,如果分配了一个,原来不是const
。但是对于这个特定的例子,std::string
可能会使用小缓冲区优化,它直接在对象中使用存储,然后最初是 const
(可能分配在只读内存中)。这符合 no 最初 const
对象可以修改的规则。
除了 read-only 内存场景之外,UB 的基本原理还包括它可以为编译器提供优化的可能性。
如juanchopanza notes in
” Optimizers use this to do all kind of crazy stuff that assumes
const
objects won't be modified.
通过修改最初的 const
对象来打破优化器的假设,可能会造成灾难性的且实际上无法预测的后果。