20

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

const Class object;

之后尝试在此类对象上调用非常量方法是未定义的行为:

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

堆分配的对象会const产生同样的后果吗?我的意思是有可能是以下情况:

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

也是未定义的行为吗?

4

6 回答 6

20

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

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;
}
于 2009-12-18T11:08:00.317 回答
11

在您的堆示例中,new返回一个指向非常量的指针。您将它存储在指向 const 的指针中(然后将其const_cast编辑回指向非 const 的指针)这一事实并没有改变对象本身不是 const 的事实,其方式与堆栈分配的对象不同是。

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

const Class* object = new const Class();

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

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

于 2009-12-18T10:50:52.253 回答
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 的指针中。

于 2009-12-18T11:23:48.723 回答
1

明显地:

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

Foo* foo = new Foo;
const_cast<int&>(foo->Bar); // don't do this.
于 2009-12-18T11:22:41.190 回答
1

不要忘记可变成员

如果 NonConstMethod 仅修改mutableconst 限定类的限定成员(参见 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!
于 2009-12-18T12:03:07.537 回答
0

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

于 2009-12-18T11:29:53.877 回答