提问者:小点点

是否允许在const定义的对象上抛弃const,只要它没有实际修改?


是否允许以下内容:

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的一致性是否可以?


共2个答案

匿名用户

是的。这是完全合法的。(这很危险,但它是合法的。)如果您(尝试)修改声明为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