通过const指针修改使用new创建的对象是否合法?

Luc*_*ore 15 c++ const language-lawyer

所以这个答案让我想到了将结果赋给new指向a的指针的场景const.AFAIK,没有理由你不能合法地 const_cast将constness带走并在这种情况下实际修改对象:

struct X{int x;};

//....
const X* x = new X;
const_cast<X*>(x)->x = 0; // okay
Run Code Online (Sandbox Code Playgroud)

但后来我想 - 如果你真的想new创建一个const对象怎么办.所以我试过了

struct X{};

//....
const X* x = new const X;
Run Code Online (Sandbox Code Playgroud)

它编译!!!

这是GCC扩展还是标准行为?我在实践中从未见过这个.如果它是标准的,我会尽可能地开始使用它.

R. *_*des 17

new 显然不会创建一个const对象(我希望).

如果要求new创建const对象,则会得到一个const对象.

没有理由你不能合法地 const_cast将constness带走并实际修改对象.

有.原因是语言规范明确地将其称为未定义的行为.所以,在某种程度上,你可以,但这意味着什么都没有.

我不知道你对此的期望是什么,但是如果你认为这个问题是在readonly内存中分配的问题,那就远远不够了.那没关系.编译器可以假设这样的对象无法相应地更改和优化,最终会出现意外结果.

  • @LuchianGrigore,如果你创建一个非const对象,然后将它分配给一个const对象指针,我相信你能够将它const_cast回一个非const指针并修改它.但我同意这个答案,你已经创建了一个const对象,所以它必须保留. (2认同)

Lig*_*ica 11

const是该类型的一部分.是否使用动态,静态或自动存储持续时间分配对象无关紧要.它仍然是const.抛弃那个const并改变对象仍然是一个未定义的操作.

constness是一种抽象,类型系统使我们能够围绕非可变对象实现安全性; 它在很大程度上帮助我们与只读内存交互,但这并不意味着它的语义仅限于这种内存.实际上,C++ 甚至不知道什么是只读存储器而不是只读存储器.

除了可以从所有通常的规则派生之外,对于动态分配的对象没有例外[lol],标准明确地提到了这一点(尽管在注释中):

[C++03: 5.3.4/1]:新的表达尝试创建的对象类型-ID(8.1)或新型-ID到其所施加.该对象的类型是已分配的类型.此类型应为完整的对象类型,但不是抽象类类型或其数组(1.8,3.9,10.4).[注意:因为引用不是对象,所以new-expression不能创建引用.] [注: 类型-ID可以是CV-合格式,在这种情况下由创建该对象的新表达具有cv修饰类型. ] [..]

[C++11: 5.3.4/1]:新的表达尝试创建的对象类型-ID(8.1)或新型-ID到其所施加.该对象的类型是已分配的类型.此类型应为完整的对象类型,但不是抽象类类型或其数组(1.8,3.9,10.4).它是实现定义的是否支持过度对齐类型(3.11).[注意:因为引用不是对象,所以new-expression不能创建引用.末端音符] [注: 类型-ID可以是CV-合格式,在这种情况下由创建该对象的新表达具有cv修饰类型. - 后注] [..]

还有一个用法示例[C++11: 7.1.6.1/4].

不确定你还有什么期望.我不能说我自己做过这件事,但我没有看到任何特别的理由.可能有一些技术社会学家可以告诉你关于我们很少动态分配东西的统计数据,只是将它视为不可变的.

  • @ JohannesSchaub-litb:我认为`x = 1;`是未定义的行为,因为你正在使用一个不再存在的对象(它的存储已被重用).当然,你必须销毁`*px`并使用placement new将原始类型的对象`int`放回到它超出范围之前. (2认同)