c++ 是否允许在常量定义的对象上丢弃常量,只要它没有被实际修改?

vxqlmq5t  于 2023-03-14  发布在  其他
关注(0)|答案(2)|浏览(135)

是否允许以下情况:

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的constness吗?它被 * 定义 * 为const,只要对象没有被实际修改,就像示例中那样。

noj0wjuj

noj0wjuj1#

是的。这是完全法律的的。(这是危险的,但它是合法的。)如果你(试图)修改一个声明为常量的对象,那么行为是未定义的。
来自n4659(C17的最后一个草稿),10.1.7.1dcl.type.cv]部分第4段:
除了声明为mutable(10.1.1)的任何类成员都可以修改之外,在const对象的生存期(6.8)内修改该对象的任何尝试都将导致未定义的行为
我强调的是,这是从C
17开始的,但这对所有版本的C都是如此。
如果您查看有关const_cast的部分,会发现
[注:根据对象的类型,通过指针、左值或指针指向const_cast(丢弃常量限定符76)产生的数据成员的写操作可能会产生未定义的行为(10.1.7.1)。- end note ]
注解并不规范,但这强烈暗示了获取一个非常量的引用或指向常量对象的指针是法律的的,而写是不允许的。
C
20的新参考:
来自N4680(C++20的最后一个草案),9.2.8.1dcl.type.cv]部分第4段:
在7.6.1.57.6.2.2const对象(6.8.3)的生存期(6.7.3)内,任何修改(7.6.19、www.example.com、www.example.com)该对象的尝试都会导致未定义的行为。
如果您查看有关const_cast的部分,7.6.1.10[expr.const.cast]第6段,链接到上述声明:
[Note:根据对象的类型,通过指针、左值或指针指向const_cast(丢弃常量限定符)生成的数据成员的写操作可能会产生未定义的行为(9.2.8.1)。]

ctehm74n

ctehm74n2#

下面的代码编译并运行,输出如下。我可以 overridearr的 * constability *,事实上,修改第一个元素成为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.04 g++编译器和Visual Studio C++中编译。它运行起来也没有问题。但上面的代码实际上是未定义的行为。它的输出:

0
2
3

相关问题