堆分配的对象可以在C ++中是const吗?

时间:2009-12-18 10:45:13

标签: c++ const const-correctness undefined-behavior

在C ++中,可以声明堆栈分配的对象const

const Class object;

之后尝试在这样的对象上调用非const方法是未定义的行为:

const_cast<Class*>( &object )->NonConstMethod(); //UB

堆分配的对象可以const具有相同的后果吗?我的意思是有可能是以下内容:

const Class* object = new Class();
const_cast<Class*>( object )->NonConstMethod(); // can this be UB?

也是未定义的行为?

6 个答案:

答案 0 :(得分:18)

是。构造和销毁const堆对象是合法的。与其他const对象一样,将其作为非const对象(例如通过指针或引用的const_cast)进行操作的结果会导致未定义的行为。

struct C
{
        C();
        ~C();
};

int main()
{
        const C* const p = new const C;

        C* const q = const_cast<C*>(p); // OK, but writes through q cause UB

        // ...

        delete p; // valid, it doesn't matter that p and *p are const

        return 0;
}

答案 1 :(得分:10)

在您的堆示例中,new返回指向非const的指针。您将它存储在指向const的指针(然后const_cast将其存储回指向非const的指针)这一事实并未改变对象本身不是const的事实,就像堆栈分配的是。

但是,你可以在堆上创建一个const对象:

const Class* object = new const Class();

在这种情况下,转换为指向非const的指针并调用非const方法将与const堆栈分配的对象相同。

(在堆上创建const对象的想法对我来说是新的,我以前从未见过。感谢Charles Bailey。)

答案 2 :(得分:2)

是的,堆分配的对象可以是const。请考虑7.1.5.1/5中示例的摘录:

const int* ciq = new const int (3);    // initialized as required
int* iq = const_cast<int*>(ciq);       // cast required
*iq = 4;                               // undefined: modifies a const object

您在问题中提供的示例很好,因为您不是要求new创建一个const对象;你只是将结果存储在指向const的指针中。

答案 3 :(得分:1)

显然:

struct Foo {
  const int Bar;
  Foo() : Bar(42) { }
};

Foo* foo = new Foo;
const_cast<int&>(foo->Bar); // don't do this.

答案 4 :(得分:1)

不要忘记 mutable 成员

如果NonConstMethod仅修改const限定类的mutable限定成员(参见7.1.5.1(4)),则不会有未确定的行为。是的,否则它是未定义的行为。

const A* p = new(const A);
A *q = const_cast<A*>(p);
q->NonConstMethodThatModifiesMembers();             // undefined behaviour!
q->NonConstMethodThatOnlyModifiesMutableMembers();  // defined behaviour!

答案 5 :(得分:0)

当对象实际上是只读时,const_cast可以导致UB(例如,当您在代码中使用硬编码字符串时,编译器可以通过将它们放置在只读的某些内存区域中来创建此类对象)由于某种原因。无论你如何保留它们的引用(const指针,const引用,等等),堆分配的对象都不会发生这种情况。