【问题标题】:Is a destructor considered a const function?析构函数是否被视为 const 函数?
【发布时间】:2012-01-12 10:25:33
【问题描述】:

考虑一下

class Foo
{
public:
    Foo(){}
    ~Foo(){}
    void NonConstBar() {}
    void ConstBar() const {}
};

int main()
{
    const Foo* pFoo = new Foo();
    pFoo->ConstBar(); //No error
    pFoo->NonConstBar(); //Compile error about non const function being invoked
    delete pFoo; //No error 

    return 0;
}

在主函数中,我同时调用 Foo

的 const 和 non const 函数

尝试调用任何非 const 函数会在 Visual Studio 中产生类似这样的错误

error C2662: 'Foo::NonConstBar' : cannot convert 'this' pointer from 'const Foo' to 'Foo &'

但delete pFoo 不会发出任何此类错误。 delete 语句必然会调用没有 const 修饰符的 Foo 类的析构函数。析构函数也可以调用其他非 const 成员函数。那么它是否是 const 函数?还是 const 指针 上的 delete 是一个特殊异常?

【问题讨论】:

  • 构造函数最肯定被认为是初始化,而不是实例的修改。析构函数也是如此。它不会修改实例,它会破坏 is。
  • ¤ 在注释参考手册定义的准标准 C++ 中,当 p 的类型为 T const* 时,您不能执行 delete p。在标准化期间(C++ 于 1998 年标准化),这条规则被颠倒过来,既不切实际又不一致。使用标准 C++ 的规则,对象在构造过程中是可变的,无论客户端代码的类型如何;如果声明的类型是const,那么它在其主要生命周期内变得不可变;最后为了破坏,构造过程被反转,这意味着它再次是可变的。这意味着您可以delete p。干杯&hth.,
  • @Alf... 我认为您的评论应该是一个答案
  • standard's paragraph。你也可以明确地销毁它。但是删除它是另一个故事(另一个段落)。

标签: c++ destructor


【解决方案1】:

您可以通过常量指针删除对象。在 C++11 中,您还可以通过 const-iterators 擦除容器元素。所以是的,从某种意义上说,析构函数始终是“常量”。

一旦调用析构函数,对象就不再存在。我想不存在的对象是否可变的问题没有实际意义。

【讨论】:

  • 我不知道我是否认同你论点的最后一部分。 const 指针旨在防止您修改对象的状态,而销毁它肯定会这样做。
  • @MarkRansom:另一方面,我只能修改存在的对象。我当然可以进入析构函数,就像任何成员函数一样;但是已经在这一步,对象不再存在——不是因为析构函数做了什么,而仅仅是因为控制流已经到达那个点。 现在析构函数可以完成它的工作,而不用考虑它对以前的对象所做的事情。
  • @MarkRansom:鉴于您可以在 C++ 中通过 const 指针销毁对象,要么 销毁它不是“修改其状态”,或 const 指针不是“旨在阻止您修改其状态”。这不是语言的意外,它完全是故意的,所以虽然你可能不喜欢它,但如果你认为破坏是修改,那么声称该语言旨在防止通过 const 指针进行所有修改是错误的。跨度>
  • @SteveJessop,我并不是说我不同意标准行为。我只是说我不认为这个论点是有效的。当您尝试销毁它仍然存在的对象时,如果这是标准所要求的,编译器很容易禁止它。正如你所说,这是故意允许的,所以我认为这一定是一个特例,而不是一个“有争议的问题”。我认为 Alf 对这个问题的评论支持了这一观点。
  • @Mark:我认为“没有实际意义”是您是否决定破坏是突变(并得出结论,作为一种特殊情况,对象可以通过 const 指针以这种方式突变),或者决定该破坏不是突变(并得出结论,对象不能通过 const 指针进行突变,但可以被破坏)。如果您专注于 Alf 所说的先前规则“不切实际”,您会得出结论,这是一个特例。如果您专注于先前的规则“不一致”,您会得出结论,这根本不是一个特殊情况,逻辑上的破坏从来都不是突变,而 ARM 弄错了。没有实际意义;-)
【解决方案2】:

对象的生命周期在析构函数被调用时结束(对于所有者/封闭范围),而不是在析构函数返回时结束。

因此,我认为删除常量没有任何问题。当你调用 delete 时,它​​已经消失了。

否则删除常量对象将需要 const_cast。

【讨论】:

  • "否则删除常量对象需要const_cast。"不,那是不可能的。 const_cast 不允许改变常量对象。它提供与非 const 正确的 API 的兼容性(指针和引用不用于改变对象,但标记为非const)以及将非const 句柄恢复为非const 对象来自const 句柄。但是任何修改常量对象的尝试都是非法的,不管你是否先使用了const_cast。它不会“解锁”常量。
猜你喜欢
  • 2014-09-27
  • 1970-01-01
  • 2012-03-18
  • 1970-01-01
  • 2021-11-10
  • 1970-01-01
  • 2010-09-26
  • 2019-12-16
  • 2017-02-27
相关资源
最近更新 更多