在构造函数中初始化,最佳实践?

时间:2009-03-31 17:40:18

标签: c++

我用C ++编程了一段时间,我使用了两种方法:

class Stuff {
public:
     Stuff( int nr ) : n( nr ) { }
private:
     int n;
}

或者

class Stuff {
public:
     Stuff( int nr ) { 
         n = nr;
     }
private:
     int n;
}

注意:这与this不同,相似但不相同。

什么是最佳做法?

7 个答案:

答案 0 :(得分:21)

首选项列表是首选。见FAQ 10.6

答案 1 :(得分:12)

使用初始化程序的一大优势:如果在初始化程序列表中的任何位置抛出异常,则将为那些已经初始化的成员调用析构函数 - 并且仅针对那些成员。

当您使用构造函数体初始化对象时,您可以正确处理异常并根据需要展开对象。这通常要难以做到。

答案 2 :(得分:5)

尽可能使用初始化列表。对于int来说,无论哪种方式都没关系,但是对于更复杂的成员对象,你最终会得到被调用对象的默认构造函数,然后是对该对象的赋值,这很可能会结束慢了。

另外,对于const成员或没有默认构造函数的成员,无论如何都必须这样做。

答案 3 :(得分:2)

如果可能,请使用第一个版本。

第一个是使用初始化列表进行初始化,并实际调用成员的构造函数。

第二个是作业。如果n是一个带有默认构造函数的类型,那么它就已经被调用了,然后你将分配给它。如果n没有默认构造函数,则会被迫使用第一种类型。同样,如果n是参考:int &n

如果没有成员的构造函数直接将其中一个参数带到构造函数中,那么添加可以为您进行转换的私有静态函数可能是值得的。

答案 4 :(得分:1)

我通常会尝试做初始化列表。首先,这使得您明确表示正在构造函数中初始化代码。 const memebers 以这种方式初始化。

如果你只是把代码放在构造函数的主体中,那么很可能有人可能决定过来并将其中的一大块移动到非构造函数“setup”例程中。

虽然可以采取过度考虑。我有一个同事喜欢创建具有2页initilizer代码的类,没有构造函数代码,并且可能有2页用于整个类的代码。我觉得这很难读。

答案 5 :(得分:0)

第二个选项不是初始化,而是赋值。对于具有用户定义的默认构造函数的类型,第二个选项将调用默认构造函数,稍后调用赋值运算符(无论是否为用户定义)来赋值。

某些类型不能默认初始化:如果您有一个没有默认构造函数的属性,保持引用(常量或不常量)或具有常量属性,则必须在初始化列表中初始化它们。

可以在初始化列表中对数组进行值初始化,但不能在构造函数体中进行值初始化:

class X {
public:
   X() : array() {} // value-initializes the array
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) array[i]=0; }    
private:
   int array[10];
};

对于POD类型,您可以在初始化列表中对它们进行值初始化,但不能在括号内进行初始化:

class X {
public:
   X() : pod() {} // value-initializes
// equivalent to (but easier to read and subtly faster as it avoids the copy):
// X() { pod = {}; } 
private:
   PODType pod;
};

最后,一些类通过使用构造函数来提供功能,这些构造函数在默认构造之后会更复杂(如果可以实现)。

class X
{
public:
   X() : v(10) {} // construct a vector of 10 default initialized integers
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) v.push_back(0); }
private:
   std::vector<int> v;
};

最后,只要它们实际上是等价的,初始化列表在C ++中就更具惯用性。

答案 6 :(得分:0)

我想补充一点,你不需要在Header(.h)上声明初始化列表。它可以在构造函数的实现中完成(这很常见)。

那么:

//Stuff.h
class Stuff {
public:
     Stuff( int nr );
private:
     int n;
}

//Stuff.cpp
Stuff::Stuff(int nr)
: n(nr)
{
    //initalize complex members
}

是合法的,imo集中了重要的字段的初始化。有时我们需要初始化正文中的复杂成员,因此您在.cpp文件中都有初始化列表和复杂的初始化。