构造函数/析构函数是否必须有代码,或者函数是否足够?

Does a constructor / destructor have to have code, or is the function enough?

本文关键字:是否 函数 或者 析构函数 构造函数 代码      更新时间:2023-10-16

如果我有一个class

class Transaction {
int no;
char dollar;
public:
    Transaction();
    ~Transaction();
}

在构造函数/析构函数

Transaction::Transaction {
    cout << "Entering constructor" << endl;
}
Transaction::~Transaction {
    cout << "Leaving program" << endl;
}

这段代码足以让构造函数和析构函数工作吗?即使我在构造函数中没有声明任何内容,它会将类中的数据成员设置为安全状态吗?

如果您提供了一个构造函数而没有为所述子对象指定初始化式,则每个子对象将被默认初始化。

标准第8.5节规定:

如果对象没有指定初始化式,则默认初始化该对象;如果不进行初始化,自动或动态存储时长的对象的值不确定。[注:具有静态或线程存储时间的对象是零初始化的,参见3.6.2。]

default-initialize类型为T的对象意味着:

  • 如果T是(可能cv限定的)类类型,则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是病态的);
  • 如果T是数组类型,则每个元素默认初始化;
  • 否则,不初始化。

如果程序调用具有const限定类型T的对象的默认初始化,则T必须是具有用户提供的默认构造函数的类类型。

初始化子对象有两种方法:在元素初始化器列表中,以及在成员声明中的大括号或相等初始化器中(对于非静态成员,后者是c++ 11中新增的)。

在实践中,这意味着当您不提供初始化式时,原始类型的变量,如intchar,将保留先前留在内存中的任何值。在大多数情况下,很难预测该值是什么,但您应该意识到它可能是剩余的敏感数据,例如密码。

对于静态存储时间变量的初始化(如命名空间范围内的对象及其成员),标准进一步规定(同一节):

在程序启动时,在进行任何其他初始化之前,每个静态存储持续时间的对象都进行零初始化。

如果没有定义构造函数,这与值初始化期间发生的情况略有不同:

T类型的对象进行值初始化意味着:

  • 如果T是具有用户提供的构造函数的类类型(可能是cv限定的),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
  • 如果T是一个(可能cv限定的)没有用户提供的构造函数的非联合类类型,则对象为零初始化,如果T隐式声明的默认构造函数是非平凡的,则调用该构造函数。
  • 如果T是数组类型,则每个元素都是值初始化的;
  • 否则,对象为零初始化。

,但效果是一样的——基本成员被设置为0,所有其他成员都调用它们的零参数构造函数。

nneonneo显式初始化所有成员的建议是好的,因为只对静态存储持续时间的变量进行零初始化通常会导致难以发现的bug。但是使用大括号或相等初始化器技术是完全可行的:

class Transaction
{
    int no = 0;
    char dollar = 0;
public:
    Transaction();
    ~Transaction();
}

你的类只有简单的数据成员,所以你甚至不需要(或者不应该想要)析构函数。

但是,应该在构造函数中初始化数据成员:
Transaction::Transaction()
  : no(0), dollar('$') {
    cout << "Entering constructor" << endl;
}

否则,它们将不会被初始化,并且可能包含随机值(如果不在构造函数中初始化原始非静态成员,则c++不保证将其初始化为任何特定值)。如果您有指针成员,这可能特别危险。

不,它不需要有代码。事实上,在大多数语言中,你可以省略它,它会正确地构造类。

相关文章: