是否允许以下内容:
const int const_array[] = { 42 };
int maybe_inc(bool write, int* array) {
if (write) array[0]++;
return array[0];
}
int main() {
return maybe_inc(false, const_cast<int *>(const_array));
}
特别是,只要对象没有像示例中那样被实际修改,放弃const_array
的一致性是否可以?
是的。这是完全合法的。(这很危险,但它是合法的。)如果您(尝试)修改声明为const的对象,则行为未定义。
源自n4659(C 17的最后草案),第10.1.7.1[dcl.type.cv]节第4段:
除了可以修改任何声明为可变(10.1.1)的类成员之外,任何在const对象的生命周期(6.8)内修改const对象的尝试都会导致未定义的行为
我的重点。这是来自C 17,但所有版本的C都是如此。
如果您查看const_cast
部分,会注意到
[注意:根据对象的类型,通过指针,左值或指向数据成员的指针进行写入操作,该操作由丢弃const-限定符76的const_cast产生,可能会产生未定义的行为(10.1.7.1)。
注释不是规范性的,但这强烈暗示获取指向const对象的非const引用或指针是合法的。不允许写入。
C 20的新参考文献:
摘自N4680(C 20的最后一稿),第9.2.8.1[dcl.type.cv]节,第4段:
在const对象的生命周期(6.7.3)中修改(7.6.19,7.6.1.5,7.6.2.2)const对象(6.8.3)的任何尝试都会导致未定义的行为。
如果您查看const_cast
一节,第7.6.1.10[expr. const.cast]para 6节链接到上述语句:
[注意:根据对象的类型,通过指针、左值或指向数据成员的指针的写操作可能会产生未定义的行为(9.2.8.1)。]
下面的代码编译并使用输出运行。我可以覆盖arr
的恒定性,事实上,将第一个元素修改为0
:
#include <iostream>
int main(int argc, char *argv[])
{
const int arr[] = {1, 2, 3};
int* parr = const_cast<int*>(arr);
parr[0] = 0;
for(auto& n : arr)
std::cout << n << std::endl;
}
上面的代码在Ubuntu 20.04g
编译器和Visual Studio C中编译。它也运行没有问题。但上面的代码实际上是未定义的行为。它的输出:
0
2
3