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

时间:2014-04-01 23:03:32

标签: c++ const language-lawyer

所以this answer让我想到了将new的结果分配给指向const的指针的情况。 AFAIK,没有理由你不能合法 const_cast constness并在这种情况下实际修改对象:

struct X{int x;};

//....
const X* x = new X;
const_cast<X*>(x)->x = 0; // okay

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

struct X{};

//....
const X* x = new const X;

并编译!!!

这是GCC扩展还是标准行为?我在实践中从未看到这一点。如果它是标准的,我会尽可能地开始使用它。

3 个答案:

答案 0 :(得分:17)

  

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

如果您要求new创建const对象,则会获得const个对象。

  

没有理由你不能合法 const_cast constness并实际修改对象。

有。原因是语言规范明确地将其称为未定义的行为。所以,在某种程度上,你可以,但这几乎没有任何意义。

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

答案 1 :(得分:11)

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

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

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

  

[C++03: 5.3.4/1]: new-expression 尝试创建 type-id (8.1)或 new-type-id 应用它。该对象的类型是已分配的类型。此类型应为完整的对象类型,但不是抽象类类型或其数组(1.8,3.9,10.4)。 [注意:因为引用不是对象,所以 new-expressions 无法创建引用。 ] [注意: type-id 可能是 cv-qualified 类型,在这种情况下,创建的对象> new-expression 具有 cv-qualified 类型。 ] [..]

     

[C++11: 5.3.4/1]: new-expression 尝试创建 type-id (8.1)或 new-type-id 应用它。该对象的类型是已分配的类型。此类型应为完整的对象类型,但不是抽象类类型或其数组(1.8,3.9,10.4)。它是实现定义的是否支持过度对齐类型(3.11)。 [注意:因为引用不是对象,所以 new-expressions 无法创建引用。 -end note] [注意: type-id 可能是 cv-qualified 类型,在这种情况下,对象是由 new-expression 具有 cv-qualified 类型。 -end note] [..]

[C++11: 7.1.6.1/4]中还提供了一个用法示例。

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

答案 2 :(得分:0)

我看待这个的方式是:

  • Xconst X以及指向它们的指针是不同的类型
  • 存在从X*const X*的隐式转换,但不是相反的转换
  • 因此以下是合法的,x在每种情况下具有相同的类型和行为

    const X * x = new X; const X * x = new const X;

唯一剩下的问题是在第二种情况下是否可以调用不同的分配器(可能在只读存储器中)。答案是否定的,标准中没有这样的规定。