删除一个指向常量的指针(T const*)

105

关于 const 指针,我有一个基本的问题。使用 const 指针时,我不能调用任何非 const 成员函数。然而,我可以在 const 指针上这样做:

delete p;

这将调用类的析构函数,本质上它是一个非const的“方法”。为什么会允许这种情况?这只是为了支持以下内容吗:

delete this;

还是有其他原因吗?

5个回答

129

这是为了支持:

// dynamically create object that cannot be changed
const Foo * f = new Foo;

// use const member functions here

// delete it
delete f;

但请注意,问题不仅限于动态创建的对象:

{
 const Foo f;
 // use it
} // destructor called here

如果不能在常量对象上调用析构函数,我们就无法使用常量对象。

24
我认为你最新的编辑非常好。这是真正的原因。对于常量对象的自动析构函数调用 - 几乎等同于删除 f;其中 f 是指向常量的指针。 - bayda
1
const Foo * fFoo const * f 不是指向常量的指针,而是指向常量 Foo 的指针。 Foo * const f 是指向常量 Foo 的常量指针。 - user11373693

58

这么说吧 - 如果不允许,就没有办法删除const对象而不使用const_cast。

从语义上讲,const表示一个对象应该是不可变的。然而,这并不意味着该对象不应该被删除。


5
析构函数可以对对象进行相当暴力的更改,因此这必须是我之前不知道的某种奇怪的“不变”的用法。 - DarthGizka
1
@DarthGizka 不,析构函数仅将你从存在对象的状态带到了不存在对象的状态。C++ 并没有定义任何观察“毁灭”后变化的方法。 - Caleth
@ Caleth:标准可能不允许您在析构函数完成后查看对象,但您肯定可以查看析构引起的副作用。因此,可以轻松安排情况使“不可变”对象的突变可观察。在美国,如果没有尸体,谋杀很难起诉,但它仍然是谋杀(并且可能有其他足以定罪的证据)。同样的区别。 - DarthGizka

5

我不允许使用const指针调用任何非const成员函数。

其实你是可以的。

class Foo
{
public:
  void aNonConstMemberFunction();
};

Foo* const aConstPointer = new Foo;
aConstPointer->aNonConstMemberFunction(); // legal

const Foo* aPointerToConst = new Foo;
aPointerToConst->aNonConstMemberFunction(); // illegal

你把一个指向非常量对象的const指针和一个指向常量对象的非const指针混淆了。
话虽如此,
delete aConstPointer; // legal
delete aPointerToConst; // legal

根据其他回答中已经给出的原因,删除任何一个都是合法的。


5

构造函数和析构函数不应被视为“方法”。它们是特殊的结构,用于初始化和拆除类的对象。

“const指针”用于指示在对象存活期间执行操作时,对象的状态不会被更改。


5
另一种看待它的方式是:const指针的确切含义是,您将无法对指向的对象进行更改,这些更改将通过该指针或任何其他指向同一对象的指针或引用可见。但是当一个对象析构时,所有指向先前被删除对象占用的地址的其他指针 不再是指向该对象的指针。它们存储相同的地址,但该地址不再是任何对象的地址(实际上,它可能很快被重用为另一个对象的地址)。
如果C++中的指针表现得像弱引用一样,即一旦对象被销毁,所有存在的指向它的指针将立即设置为0,那么这种区别将更加明显。(这种行为被认为在运行时对所有C++程序来说代价太高,事实上它是不可能完全可靠的。) 更新:九年后重新阅读此文,感觉有点像律师文件。我现在认为您最初的反应是可以理解的。禁止变异但允许销毁显然是有问题的。 const指针/引用的暗示契约是它们的存在将作为目标对象的销毁块,也称为自动垃圾回收。
通常的解决方案是使用几乎任何其他语言。

如果你无法销毁指向 const 的指针所指的对象,那么当一个 std::unique_ptr<const T> 结束其生命周期时,你该如何处理呢? - Caleth
1
@Caleth 那在 C++ 中就没有解决方案了。这只是一个普遍问题的例子:在 C++ 中,const 修饰符意味着“你不能改变目标,除了一种情况,你可以完全破坏它,并使所有其他引用无效并成为未定义行为的来源”。这就是为什么我认为这种类型的问题应该作为考虑其他语言的提示。它有 UB 漏洞,如果不采取不同的基本方法,就无法解决。 - Daniel Earwicker

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