为什么 C++对象有默认的析构函数吗?

发布于 2024-10-14 21:31:50 字数 204 浏览 5 评论 0原文

例如,当我没有声明构造函数时,编译器将为我提供一个默认构造函数,该构造函数没有参数,也没有定义(空主体),因此将不执行任何操作

因此,例如,如果我完成了一个对象,默认析构函数不会重新分配该对象使用的(释放)内存吗?如果没有,我们为什么要得到它?

而且,也许同样的问题也适用于默认构造函数。如果它什么都不做,为什么默认为我们创建它?

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

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

悸初 2024-10-21 21:31:50

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

  1. 它调用基类的默认构造函数。
  2. 如果类是多态的,它会初始化 vtable 指针。
  3. 它调用所有拥有它们的成员的默认构造函数。如果某个成员具有一些构造函数,但没有默认构造函数,则这是一个编译时错误。

而且,仅当类不是多态的、没有基类并且没有需要构造的成员时,编译器生成的默认构造函数才会执行任何操作。但即便如此,出于其他答案中解释的原因,有时也需要默认构造函数。

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

但内存分配实际上与此无关。内存在调用构造函数之前分配,并且仅在最后一个析构函数完成后才释放。

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.

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.

假装爱人 2024-10-21 21:31:50

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

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

A a;  // Oh dear!  Compilation error

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

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.

溺孤伤于心 2024-10-21 21:31:50

使用智能指针时,默认析构函数(请参阅 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;
}

这里的输出显示仅 foo2 发生泄漏:

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

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

#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:

Foo(1)
Foo(2)
Foo(0)
Foo(0)
in main()
~Foo(0)
~Foo(0)
~Foo(1)
羁拥 2024-10-21 21:31:50

默认析构函数不会执行任何操作(就像默认构造函数一样)。

如果您的析构函数实际上需要执行某些操作(例如:释放一些资源),您需要自己定义一个。

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

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

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).

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.

生寂 2024-10-21 21:31:50

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

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

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

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 struct in 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.

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 overrider being applied to the method in the base class. In the base class, it does not override anything, 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 overrider will 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.

半葬歌 2024-10-21 21:31:50

简而言之,在 C++ 中,每个对象都需要一个构造函数和一个析构函数,即使它们不执行任何操作。因此,编译器在后台为您创建它们满足了这一要求。

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

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.

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.)

心在旅行 2024-10-21 21:31:50

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

至于默认构造函数部分,我将引用关于此的 Wikipedia 文章...

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

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

在上面
情况下,如果
类没有默认值
构造函数。编译器将
隐式定义默认值
构造函数

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

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 article on 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.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文