【问题标题】:Destructor of a class implicitly defined隐式定义的类的析构函数
【发布时间】:2012-01-23 16:31:39
【问题描述】:

考虑没有开发人员明确声明的destructorconstructor 的类的情况。我知道在这种情况下,一个班级的destructor 将是implicitly declared。那么destructor是不是真的implicitly defined,只有在类的一个对象即将被销毁的时候?

构造函数的行为是否也和上面一样。 implicitly defined是不是只有在创建类的对象的时候?

编辑

class A {
  public:

};
int main() {

}

在上面的代码中,~A() 将被隐式声明。我的问题是,只有当类的对象被实例化时,析构函数的定义是否真的会被隐式地进行

class A {
      public:

    };
    int main() {
      A a;
    }

还是隐式定义,即使对象实例化没有完成?

【问题讨论】:

  • 如果你能解释为什么这很重要,也许我们可以给出更好的答案。
  • 您是否对implicitly declaredimplicitly defined 进行了某种区分?我真的很难理解这个问题......
  • 为了清楚起见,我添加了一些代码 sn-p。
  • @LinuxPenseur:你需要这个做什么?
  • @phresnel :我正在学习 C++ 语言的基础知识。我想对正在发生的事情有一个具体的了解。如果在我掌握了语言之后有人问我这个问题,我应该能够给出正确的答案。

标签: c++ constructor destructor explicit-constructor


【解决方案1】:

是的,隐式声明的默认构造函数和析构函数在用于创建或销毁对象实例时被隐式定义。用标准(C++11)的话来说:

12.1/6: 一个默认构造函数被默认且未定义为已删除,当它被 odr-used 时隐式定义 (3.2) 创建其类类型 (1.8) 的对象,或者在其第一次声明后显式默认。

12.4/5:默认且未定义为已删除的析构函数在 odr 使用 (3.2) 时被隐式定义 销毁其类类型 (3.7) 的对象,或者在其第一次声明后显式默认。

所以它们是在您的第二个代码 sn-p 中定义的,它创建和销毁 A 类型的对象,但不是在第一个代码中,它没有。

【讨论】:

    【解决方案2】:

    一方面,通常不可能确定一个对象是否在任何重要的程序中被创建/销毁*,另一方面,只要可观察的行为保持不变,这并不重要.

    但是,defined when object created/destroyeddefined if needed 之间有一条细线。在下面的示例中,需要定义Foo::Foo(),因为有可能需要它。但是,你问是否在创建对象时定义,后者是不可判定的。


    *:

    class Foo {};
    int main(int argc, char *argv[]) {
        if (argc>1) Foo(); // <- impossible to decide if ever constructed/destroyed
    }
    
    // On the other hand, compiler might be smart enough to observe that
    // Foo does not have any visible behaviour, remove Foo entirely, and in
    // effect spit out this:
    int main() {}
    

    【讨论】:

    • 始终可以确定程序是否需要包含代码来创建或销毁对象(正如您的示例清楚地所做的那样);这决定了是否定义了隐式构造函数或析构函数。
    • @Mike Seymour:当然你是对的,但是 OP 基本上不是问is defined if needed?,而是问is defined _when_ object is created(我更新了我的帖子,希望让它更清楚)。
    【解决方案3】:

    函数是否定义不是在运行时确定的,所以析构函数不能“定义,只有当对象[..]即将被销毁时 em>”只是因为您的可执行文件是静态的,而不是为特定运行创建的。

    但是,如果最终可执行文件中不存在对析构函数的调用,则链接器可能选择 完全删除该函数。


    最后一点,考虑这个例子:

    class A {
      A() {}
      ~A() {}
    };
    class B {
      A a; // cannot access dtor nor ctor of A
    };
    

    如果您从未实例化过B,这实际上会编译和链接,因为没有B::B()B::~B() 不会被合成。但是,如果您尝试创建 B 的对象,编译器会调用您一些丰富多彩的名称,仅仅是因为您强制它合成了 B::B()B::~B(),这是它无法做到的。

    【讨论】:

    • 如果不存在对析构函数的调用,那么编译器根本不会定义析构函数,因为这是标准所说的。你的例子不仅仅靠运气。它之所以有效,是因为除非实例化 B,否则未定义构造函数。
    • @MikeSeymour:编译器是怎么知道的?可以由其他编译单元进行调用吗?
    • 处理内联函数的方式相同。构造函数/析构函数在每个需要它的翻译单元中定义,如有必要,链接器会整理出重复项。
    猜你喜欢
    • 2010-10-01
    • 1970-01-01
    • 2014-08-26
    • 2021-11-20
    • 2014-12-02
    • 2018-10-05
    • 2017-12-03
    • 2018-06-11
    相关资源
    最近更新 更多