$ 5.2.11 / 7 - “[注:取决于 对象的类型,写操作 通过指针,左值或指针 由a产生的数据成员 const_cast抛弃了一个 const-qualifier68)可能生成 未定义的行为(7.1.5.1)。 ]“
本节的措辞(C ++ 03)让我感到惊讶。令人惊讶的是两件事。
a)首先,使用'可能'。为什么'可能'?标准中的其他地方对未定义的行为非常明确
b)为什么抛弃原始const对象的常量而不是直接'未定义的行为'。为什么要触发UB需要写入?
答案 0 :(得分:4)
a)首先,使用'可能'。为什么是 有可能'?标准中的其他地方 非常明确的 未定义的行为
不要过分深入研究 may 这个词的用法。关键是,在这种情况下抛弃constness会导致未定义的行为。
C ++标准经常使用“可能”或“可能”,如:
1.3.12:本国际时也可以预期未定义的行为 标准省略了任何描述 行为的明确定义。
强调我的。基本上,该标准使用“可能”一词,如“is allowed to”。
b)为什么抛弃了 原始const对象的constness 不是直接'未定义 行为'。为什么写是 是否需要触发UB?
写入触发UB,因为const对象可能存储在某些平台的只读内存中。
答案 1 :(得分:3)
我的理解是,如果有问题的对象基本上是一个const对象而不是一个const指针或对一个最初不是const的对象的引用,它将只是UB。
这个想法是基本上const的数据可以加载到内存的只读部分,而写入它只是不起作用。但是,如果有问题的对象基本上是可变的,那么它可以保证正常工作。
例如:
const int x = 4;
const int *y = x;
*const_cast<int*>(x) = 3; // UB - the pointed-to object may
// be in read-only memory or whatever.
int a = 7;
const int *b = a;
*const_cast<int*>(b) = 6; // Not UB - the pointed-to object is
// fundamentally mutable.
对于下面的评论,因为代码在评论中看起来很糟糕:
在标准的§7.1.5.1/ 4中,给出的例子是:
int i = 2;
const int * cip; // pointer to const int
cip = &i; // OK: cv-qualified access path to unqualified
...
int* ip;
ip = const_cast <int *>( cip ); // cast needed to convert const int* to int*
*ip = 4; // defined: *ip points to i, a non-const object
所以这是特别允许的。
答案 2 :(得分:3)
对于您的第一个问题,如果某些可能产生未定义的行为,那么这不会使其变得不那么明确。
对于第二部分,我认为这是出于互操作性的原因。例如,C不会(或者在C99之前没有)具有const
关键字,因此如果要将const对象传递给C函数,则必须抛弃常量。所以C ++标准规定只要不执行写操作就允许这样做。如果C函数是只读的,则可以安全地抛弃常量。
即使在C ++中,不一致或不完整的const正确性也很常见。因此,我们偶尔会遇到这样的情况,即我们必须抛弃const,以便将const对象传递给不修改其参数的函数,但是将它取为非const。
答案 3 :(得分:1)
我认为这是因为const
对象可以存储到只读内存中。因此,写入它可能会产生许多不同的影响:程序崩溃,分段错误或无效。