Initializing in constructors, best practice?

2020-02-01 19:47发布

I've been programming in C++ a while and I've used both methods:

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

Or

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

Note: This is not the same as this, similar but not the same.

What is considered best practice?

标签: c++
7条回答
Viruses.
2楼-- · 2020-02-01 19:53

I generally try to do the initializer list when I can. For one thing, this makes it explicit that you are initializing code in the constructor. const memebers have to be initialized this way.

If you just put code in the constructor's body, it is quite possible someone may decide to come along and move a big chunk of it into a non-constructor "setup" routine later.

It can be taken overboard though. I have a coworker who likes to create classes that have 2 pages of initilizer code, no constructor code, and perhaps 2 pages for the entire rest of the class' code. I find that really tough to read.

查看更多
地球回转人心会变
3楼-- · 2020-02-01 19:56

The second option is not initialization but assignment. With types that have user defined default constructors, the second option will call the default constructor and later on call the assignment operator (whether user defined or not) to assign the value.

Some types cannot be default initialized: If you have an attribute without default constructor, hold references (constant or not) or have constant attributes they must be initialized in the initializer list.

Arrays can be value-initialized in the initialization list, but not in the constructor body:

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];
};

For POD types, you can value-initialize them in the initialization list but not inside the brackets:

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;
};

Finally, some classes offer functionality through the use of constructors that will be more complex (if achievable) after default construction.

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;
};

Last, whenever they are in fact equivalent, initialization lists are more idiomatic in C++.

查看更多
够拽才男人
4楼-- · 2020-02-01 20:00

If possible, use the first version.

The first is initializing using intializer lists, and actually calls the constructors of the members.

The second is assignment. If n was of a type with a default constructor, it the would have already been called, and then you'd be assigning to it. If n didn't have a default constructor, you'd be forced to use the first type. Likewise if n was a reference: int &n.

If there are no constructors of you members that directly take one of the parameters to your constructor, it may be worthwhile to add private static functions that can do the conversion for you.

查看更多
三岁会撩人
5楼-- · 2020-02-01 20:05

Initializer lists are preferred. See FAQ 10.6

查看更多
做个烂人
6楼-- · 2020-02-01 20:07

I want to add that you don't need to declare the initializer list on the Header (.h). It can be done at the implementation of the constructor (which is very common).

So then:

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

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

is legal and imo concentrates the initialization of fields where it matters. Sometimes we need to initialize complex members in the body, so you have your initializer list and the complex initialization all in the .cpp file.

查看更多
再贱就再见
7楼-- · 2020-02-01 20:09

One big advantage to using initializers: If an exception is thrown anywhere within the initializer list, the destructors will be called for those members that had already been initialized -- and only for those members.

When you use the contructor body to initialize the object, it's up to you to handle exceptions properly and unwind the object as appropriate. This is usually much harder to get right.

查看更多
登录 后发表回答