5

$5.2.11/7 - "[注意:根据对象的类型,通过指针、左值或指向数据成员的指针的写操作由 const_cast 产生,该 const_cast 丢弃了 const-qualifier68)可能会产生未定义的行为 (7.1. 5.1).]"

本节 (C++03) 的措辞令我惊讶。令人惊讶的是两件事。

a) 首先,使用“may”。为什么是“可能”?标准中的其他地方对未定义的行为非常明确

b)为什么放弃最初的 const 对象的 const 性不是立即“未定义的行为”。为什么触发UB需要写入?

4

4 回答 4

6

a) 首先,使用“may”。为什么是“可能”?标准中的其他地方对未定义的行为非常明确

不要太深入地研究“可能”这个词的用法。关键是,在这种情况下抛弃 constness 会导致未定义的行为。

C++ 标准经常使用“may”或“might”,例如:

1.3.12:当本国际标准省略对任何明确的行为定义的描述时,也可能出现未定义的行为。

强调我的。基本上,该标准使用“允许”中的“可能”一词。

b)为什么放弃最初的 const 对象的 const 性不是立即“未定义的行为”。为什么触发UB需要写入?

写入会触发 UB,因为 const 对象可能会存储在某些平台上的只读内存中。

于 2010-10-28T12:02:30.320 回答
5

我的理解是,如果所讨论的对象基本上是 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

所以这是特别允许的。

于 2010-10-28T12:01:27.400 回答
3

对于您的第一个问题,如果某些事情可能会产生未定义的行为,那么这并不会使它变得不那么未定义。

对于第二部分,我想这是出于互操作性的原因。例如,C 没有(或在 C99 之前没有)有const关键字,所以如果你想将 const 对象传递给 C 函数,就必须抛弃 const 。因此,C++ 标准规定只要不执行写入,就允许这样做。如果 C 函数是只读的,则可以安全地丢弃常量。

即使在 C++ 中,不一致或不完整的 const 正确性也很常见。所以我们偶尔会遇到我们必须抛弃 const-ness 以便将 const 对象传递给不修改其参数但通过非 const 获取它的函数的情况。

于 2010-10-28T12:13:07.070 回答
1

我相信这是因为一个const对象可以存储到只读内存中。因此,写入它可能会产生许多不同的影响:程序崩溃、分段错误或无效。

于 2010-10-28T12:01:08.213 回答