Sim*_*ity 51 c++ constructor destructor default-constructor
当我没有声明constructor例如,编译器将为我提供一个default constructor没有参数和没有定义(正文)的东西,因此,不会采取任何行动.
如果我现在不声明a destructor,编译器将为我提供一个default destructor没有defintion(正文),因此,我认为没有动作.
所以,如果我完成了一个对象,例如,对象使用的default destructor重新分配(免费)内存是不是?如果没有,为什么我们得到它?
并且,也许同样的问题适用于default constructor.如果它什么都没有,为什么它默认为我们创建?
谢谢.
Ser*_*nov 69
说编译器生成的默认构造函数不采取任何操作是错误的.它等同于用户定义的构造函数,其中包含一个空主体和一个空的初始化列表,但这并不意味着它不采取任何操作.这是它的作用:
并且只有当一个类不是多态的,没有基类并且没有需要构造的成员时,编译器生成的默认构造函数才会执行任何操作.但即便如此,由于其他答案中解释的原因,有时也需要默认构造函数.
析构函数也是如此 - 它调用基类的析构函数和具有它们的所有成员的析构函数,因此在一般情况下,编译器生成的析构函数不执行任何操作.
但内存分配实际上与此无关.在调用构造函数之前分配内存,并且只有在最后一个析构函数完成后才释放它.
使用智能指针时,默认析构函数(请参阅 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;
}
Run Code Online (Sandbox Code Playgroud)
此处的输出显示仅针对foo2以下情况发生泄漏:
Foo(1)
Foo(2)
Foo(0)
Foo(0)
in main()
~Foo(0)
~Foo(0)
~Foo(1)
Run Code Online (Sandbox Code Playgroud)
因为如果您没有任何(可公开访问的)构造函数或析构函数,则无法实例化该类的对象.考虑:
class A
{
private:
A() {}
~A() {}
};
A a; // Oh dear! Compilation error
Run Code Online (Sandbox Code Playgroud)
如果未显式声明任何构造函数或析构函数,则编译器必须提供一个以允许创建对象.
默认构造函数和析构函数只是一种商品,以防您不需要对类进行任何特殊处理,您不需要手动编写空版本。这在其他 OO 语言中很常见,例如在 Java 中,如果成员的零初始化就足够了,则不需要提供构造函数。同时,它是与 C 向后兼容的要求。如果你struct在 C 中有 a ,它将没有构造函数或析构函数(C 没有这些概念),以便能够在 C++ 中处理那些必须是有效代码。
另一种选择是在语言中声明一个类可以没有构造函数或析构函数,但是整个语言规范必须处理这样一个事实,即某些类型可能具有构造函数和析构函数而其他类型没有,这将使语言更复杂,更难指定。虽然具有隐式定义的版本不会改变行为并简化规范。
在这个级别上,它就像将术语覆盖应用于基类中的方法。在基类中,它没有覆盖任何东西,没有任何东西可以覆盖!然而,该语言明确指出,在基类中声明的虚拟非纯方法是覆盖程序。这使规范能够简单地说明当通过指针或引用调用方法时将调用最终覆盖程序,而无需添加 extre * 或基方法实现,如果该特定层次结构中的特定方法不存在覆盖程序。
默认析构函数无法知道您的类“拥有”哪些内存来释放它。
至于默认构造函数部分,我将引用维基百科关于此的文章......
在 C++ 中,默认构造函数很重要,因为它们在某些情况下会自动调用:
- 当声明一个对象值时不带参数列表,例如 MyClass x;; 或动态分配,不带参数列表,例如 new MyClass;默认构造函数用于初始化对象
- 当声明一个对象数组时,例如 MyClass x[10];;或动态分配,例如 new MyClass [10];默认构造函数用于初始化所有元素
- 当派生类构造函数未显式调用其初始值设定项列表中的基类构造函数时,将调用基类的默认构造函数
- 当类构造函数未显式调用其初始值设定项列表中的对象值字段之一的构造函数时,将调用该字段的类的默认构造函数
- 在标准库中,当未显式给出值时,某些容器会使用默认构造函数“填充”值,例如 vector(10);用 10 个元素初始化向量,其中填充了我们类型的默认构造值。
在上述情况下,如果类没有默认构造函数,则会出错。编译器会隐式定义一个默认构造函数
如果没有为类显式定义构造函数。此隐式声明的默认构造函数等效于使用空白主体定义的默认构造函数。(注意:如果定义了一些构造函数,但它们都是非默认的,则编译器不会隐式定义默认构造函数。这意味着一个类可能不存在默认构造函数。)