C++ 默认析构函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4837223/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:42:04  来源:igfitidea点击:

C++ default destructor

c++constructordestructordefault-constructor

提问by Simplicity

When I don't declare a constructorfor example, the compiler will provide me with a default constructorthat will have no arguments and no definition (body), and thus, will take no action.

constructor例如,当我不声明 a 时,编译器将为我提供一个default constructor没有参数和定义(主体)的 a ,因此不会采取任何行动

If I now don't declare a destructor, the compiler will provide me with a default destructorwith no defintion (body), and thus, I think no action.

如果我现在不声明 a destructor,编译器将为我提供一个default destructor没有定义(主体)的 a ,因此,我认为没有 action

So, if I'm finished with an object for example, wouldn't the default destructorreallocate (free) memory used by the object? If it doesn't, why are we getting it?

因此,例如,如果我完成了一个对象,则不会default destructor重新分配该对象使用的(空闲)内存吗?如果没有,我们为什么要得到它?

And, maybe the same question applies to the default constructor. If it doesn nothing, why is it created for us by default?

而且,也许同样的问题适用于default constructor. 如果它什么都不做,为什么它默认为我们创建?

Thanks.

谢谢。

回答by Sergei Tachenov

It's wrong to say that a compiler-generated default constructor takes no action. It is equivalent to a user-defined constructor with an empty body and an empty initializer list, but that doesn't mean it takes no action. Here is what it does:

说编译器生成的默认构造函数不采取任何行动是错误的。它相当于一个用户定义的构造函数,它具有一个空的主体和一个空的初始值设定项列表,但这并不意味着它不采取任何行动。这是它的作用:

  1. It calls the base class'es default constructor.
  2. It initializes the vtable pointer, if the class is polymorphic.
  3. It calls the default constructors of all members that have them. If there is a member with some constructors, but without a default one, then it's a compile-time error.
  1. 它调用基类的默认构造函数。
  2. 如果类是多态的,它会初始化 vtable 指针。
  3. 它调用所有拥有它们的成员的默认构造函数。如果某个成员有一些构造函数,但没有默认构造函数,那么这是一个编译时错误。

And only if a class is not polymorphic, has no base class and has no members that require construction, then a compiler-generated default constructor does nothing. But even then a default constructor is sometimes necessary for the reasons explained in other answers.

并且只有当一个类不是多态的,没有基类并且没有需要构造的成员时,编译器生成的默认构造函数什么都不做。但即使如此,由于其他答案中解释的原因,有时也需要默认构造函数。

The same goes for the destructor - it calls base class'es destructor and destructors of all members which have them, so it isn't true in general case that a compiler-generated destructor does nothing.

析构函数也是如此——它调用基类的析构函数和所有拥有它们的成员的析构函数,所以在一般情况下编译器生成的析构函数不执行任何操作是不正确的。

But memory allocation really has nothing to do with this. The memory is allocated before the constructor is called, and it is freed only after the last destructor has finished.

但是内存分配确实与此无关。内存在调用构造函数之前分配,只有在最后一个析构函数完成后才会释放。

回答by Oliver Charlesworth

Because if you don't have any (publiclly-accessible) constructors or destructors, then an object of the class cannot be instantiated. Consider:

因为如果您没有任何(可公开访问的)构造函数或析构函数,则无法实例化该类的对象。考虑:

class A
{
private:
    A() {}
    ~A() {}
};

A a;  // Oh dear!  Compilation error

If you don't explicitly declare any constructors or destructors, the compiler must provide one to allow creation of objects.

如果您没有显式声明任何构造函数或析构函数,编译器必须提供一个以允许创建对象。

回答by Ulrich Stern

When using smart pointers, the default destructor (see Sergey's answer) can be critical to avoid memory leaks. Here an example:

使用智能指针时,默认析构函数(请参阅 Sergey 的回答)对于避免内存泄漏至关重要。这里有一个例子:

#include <iostream>
#include <memory>

using namespace std;

class Foo {
public:
  Foo(int n = 0): n(n) { cout << "Foo(" << n << ")" << endl; }
  ~Foo() { cout << "~Foo(" << n << ")" << endl; }
private:
  int n;
};

// notes:
// * default destructor of Bar calls destructors of unique_ptr<Foo> foo
//  and of unique_ptr<Foo[]> foo3, which, in turn, delete the Foo objects
// * foo2's Foo object leaks
class Bar {
public:
  Bar(): foo(new Foo(1)), foo2(new Foo(2)), foo3(new Foo[2]) { }
private:
  unique_ptr<Foo> foo;
  Foo* foo2;
  unique_ptr<Foo[]> foo3;
};

int main() {
  Bar bar;
  cout << "in main()" << endl;
}

Here the output, showing that a leak occurs only for foo2:

此处的输出显示仅针对foo2以下情况发生泄漏:

Foo(1)
Foo(2)
Foo(0)
Foo(0)
in main()
~Foo(0)
~Foo(0)
~Foo(1)

回答by peoro

Default destructor won't do anything (just like a default constructor).

默认析构函数不会做任何事情(就像默认构造函数一样)。

You'll need to define one yourself, if your destructor actually needs to do something (eg: freeing some resources).

如果您的析构函数确实需要做某事(例如:释放一些资源),您需要自己定义一个。

Note that usually you should follow the rule of three: if your program needs to do something in its destructor (eg: freeing resources) you should also provide a copy constructor and an assignment operator; C++ also provides default versions of them (which, again, won't do anything).

请注意,通常您应该遵循三原则:如果您的程序需要在其析构函数中执行某些操作(例如:释放资源),您还应该提供一个复制构造函数和一个赋值运算符;C++ 还提供了它们的默认版本(同样,它不会做任何事情)。

Default constructor/destructor/assignment operator/copy constructor are useful when you're handling simple classes where you don't need to do anything. A special case are POD: they (prior to C++0x) even cannot have explicit constructors or destructor.

当您处理不需要做任何事情的简单类时,默认构造函数/析构函数/赋值运算符/复制构造函数非常有用。一个特例是 POD:它们(在 C++0x 之前)甚至不能有显式构造函数或析构函数。

回答by David Rodríguez - dribeas

The default constructor and destructors are just a commodity in case you do not need anything special done with your class you do not need to write an empty version manually. This is common to other OO languages, for example in Java you do not need to provide a constructor if zero initialization of the members suffices. At the same time it is a requirement for backwards compatibility with C. If you have a structin C, it will not have constructor or destructor (C does not have those concepts), to be able to handle that code in C++ that has to be valid code.

默认构造函数和析构函数只是一种商品,以防您不需要对类进行任何特殊处理,您不需要手动编写空版本。这在其他 OO 语言中很常见,例如在 Java 中,如果成员的零初始化就足够了,则不需要提供构造函数。同时,它是与 C 向后兼容的要求。如果你struct在 C 中有 a ,它将没有构造函数或析构函数(C 没有这些概念),以便能够在 C++ 中处理那些必须是有效代码。

Another option would have been declaring in the language that a class could have no constructor or destructor, but then the whole language spec would have to deal with the fact that some types might have constructors and destructors while others don't, and that will make the language more complex and harder to specify. While having that implicitly defined versions does not change the behavior and eases the specification.

另一种选择是在语言中声明一个类可以没有构造函数或析构函数,但是整个语言规范必须处理这样一个事实,即某些类型可能具有构造函数和析构函数而其他类型没有,这将使语言更复杂,更难指定。虽然具有隐式定义的版本不会改变行为并简化规范。

At this level it is like the term overriderbeing applied to the method in the base class. In the base class, it does not overrideanything, there is nothing to override! And yet the language explicitly states that a virtual non-pure method declared in a base is an overrider. This enables the spec to simply say that the final overriderwill be called when the method is called through a pointer or reference without having to add an extre *or the base method implementation if no overrider exists for that particular method in that particular hierarchy.

在这个级别上,它就像将术语覆盖应用于基类中的方法。在基类中,它没有覆盖任何东西,没有任何东西可以覆盖!然而,该语言明确指出,在基类中声明的虚拟非纯方法是覆盖程序。这使规范能够简单地说明当通过指针或引用调用方法时将调用最终覆盖程序,而无需添加 extre * 或基方法实现,如果该特定层次结构中的特定方法不存在覆盖程序。

回答by SoapBox

The short answer is that in C++ every object needs a constructor and a destructor, even if they don't do anything. So the compiler creating them for you in the background satisfies this requirement.

简短的回答是,在 C++ 中,每个对象都需要一个构造函数和一个析构函数,即使它们什么都不做。所以在后台为你创建它们的编译器满足了这个要求。

A longer answer is that the constructors are responsible for initialization of members of the class. The default constructor does default initialization of all of the members. (That doesn't mean anything for POD types, but other classes get their default constructors called.)

更长的答案是构造函数负责类成员的初始化。默认构造函数对所有成员进行默认初始化。(这对 POD 类型没有任何意义,但其他类会调用它们的默认构造函数。)

回答by Andrew White

A default destructor would have no way of knowing what memory your class "owns" to be able to free it.

默认析构函数无法知道您的类“拥有”哪些内存以释放它。

As to the default constructor part, I will quote the Wikipedia articleon this one...

至于默认的构造函数部分,我将引用维基百科上关于这个的文章......

In C++, default constructors are significant because they are automatically invoked in certain circumstances:

  • When an object value is declared with no argument list, e.g. MyClass x;; or allocated dynamically with no argument list, e.g. new MyClass; the default constructor is used to initialize the object
  • When an array of objects is declared, e.g. MyClass x[10];; or allocated dynamically, e.g. new MyClass [10]; the default constructor is used to initialize all the elements
  • When a derived class constructor does not explicitly call the base class constructor in its initializer list, the default constructor for the base class is called
  • When a class constructor does not explicitly call the constructor of one of its object-valued fields in its initializer list, the default constructor for the field's class is called
  • In the standard library, certain containers "fill in" values using the default constructor when the value is not given explicitly, e.g. vector(10); initializes the vector with 10 elements, which are filled with the default-constructed value of our type.

In the above circumstances, it is an error if the class does not have a default constructor. The compiler will implicitly define a default constructor

if no constructors are explicitly defined for a class. This implicitly-declared default constructor is equivalent to a default constructor defined with a blank body. (Note: if some constructors are defined, but they are all non-default, the compiler will not implicitly define a default constructor. This means that a default constructor may not exist for a class.)

在 C++ 中,默认构造函数很重要,因为它们在某些情况下会自动调用:

  • 当一个对象值被声明为没有参数列表时,例如 MyClass x;; 或者不带参数列表动态分配,例如 new MyClass;默认构造函数用于初始化对象
  • 当一个对象数组被声明时,例如 MyClass x[10];; 或动态分配,例如 new MyClass [10];默认构造函数用于初始化所有元素
  • 当派生类构造函数未在其初始化列表中显式调用基类构造函数时,将调用基类的默认构造函数
  • 当类构造函数未显式调用其初始值设定项列表中的对象值字段之一的构造函数时,将调用该字段类的默认构造函数
  • 在标准库中,某些容器在未明确给出值时使用默认构造函数“填充”值,例如 vector(10);用 10 个元素初始化向量,这些元素填充了我们类型的默认构造值。

在上述情况下,如果类没有默认构造函数是错误的。编译器会隐式定义一个默认构造函数

如果没有为类显式定义构造函数。这个隐式声明的默认构造函数等价于使用空白主体定义的默认构造函数。(注意:如果定义了一些构造函数,但它们都是非默认的,编译器不会隐式定义默认构造函数。这意味着对于一个类可能不存在默认构造函数。)