const_cast解引用指针是否总是会导致未定义行为?

3
请看下面的内容:
struct A
{
    std::string* get() const
    {
        //return const_cast<std::string*>(&m_pObj);
        return &const_cast<A*>(this)->m_pObj;
    }

    std::string m_pObj;
};

this进行const_cast然后解除const属性再进行操作是否会产生未定义行为?有没有一种情况可以在用const_cast取消指针的常量性后解除引用却不会导致未定义行为?

(我知道上面的示例是糟糕的实践和设计,可以使用mutable解决 - 但这不是重点)

4个回答

9
const_cast是什么?对this指针进行const_cast转换是否会导致未定义行为?在什么情况下,解引用const_cast所得到的指针不会产生未定义行为?
并非总是会产生未定义行为。只有当对象常量 (如A const x;)且对解引用进行了修改数据的操作时,才会发生未定义行为。如果仅用于读取,则不会产生未定义行为。如果对象不是常量(可能完全不是,也可能是一个非常量对象的const引用),则不会发生未定义行为。

3
不,只有当引用的对象最初被声明为const并且您随后修改了强制转换获得的数据时,才会出现未定义行为(§5.2.11/7和§7.1.6.1/4)。以下操作是合法的:
A a;
a.get()->clear();

虽然这不是标准行为(因此是未定义的):

A const a;
a.get()->clear();

4
只要取消引用不用于修改对象,就没有未定义行为。也就是说:A const a; std::cout << *a.get(); 是可以的,但 a.get()->clear(); 不可以。 - David Rodríguez - dribeas
@David 是的,看更新。哦,我更喜欢你的例子(->clear())而不是我的(解引用+修改[0]),所以我偷了它,希望你不介意。 - Konrad Rudolph

1

不行。具体来说:

5.2.2 函数调用

5 [注:函数可以更改其非const参数的值,但这些更改不能影响参数的值,除非参数是引用类型(8.3.2);如果引用是const限定类型,则需要使用const_cast来去除constness以修改参数的值。如果需要,将引入临时对象,其中一个参数是const引用类型(7.1.6、2.14、2.14.5、8.3.4、12.2)。此外,还可以通过指针参数修改非常量对象的值。——注释结束]

然而,

5.2.11 const_cast
12 [注意:某些涉及仅在cv限定符上进行更改的转换不能使用const_cast进行。例如,指向函数的指针之间的转换未涵盖,因为这种转换会导致使用其值引起未定义行为。出于同样的原因,指向成员函数的指针之间的转换,特别是从指向const成员函数的指针到指向非const成员函数的指针的转换,也未涵盖。-注释结束]

0

编译器可以自由地将const值存储在只读内存中,并且在优化程序时可以做出它永远不会改变的假设。如果您去除const属性,那么您就会违反与编译器的契约,因此从技术上讲,任何事情都可能发生。

实际上,编译器很少会执行一些被const_cast破坏的操作,但理论上是有可能的。


之前的答案哪一个是不正确的?它们都说尝试修改const对象是未定义的行为。去除const是完全合法的,总是可以的,并且如果对象本身不是const,则通过转换的结果修改对象也是合法的(并且定义良好的)。 - James Kanze
你是对的(我已经删除了那个陈述)。我读得有点太快了。所有的开始都是“不”或“不总是”,这似乎是错误的,但仔细阅读后我发现他们已经充分限定了。抱歉。 - Michael J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接