seg.server.fault
seg.server.fault

Reputation: 20018

C++ constructor definition

All of the constructors methods here do the same thing. I mostly use method2 but saw method3 for the first time today. Have seen method1 in some places but dont know what are the exact differences between them ? Which one is the best way to define constructors and why ? Is there any performance issues involved ?

  1 class Test
  2 {
  3     private:
  4         int a;
  5         char *b;
  6     public:
  7         Test(){};
  8         
  9         // method 1
 10         Test(int &vara, char *& varb) : a(vara), b(varb){}
 11         
 12         // method 2
 13         Test(int &vara, char *& varb)
 14         {
 15             a = vara;
 16             b = varb;
 17         }   
 18         
 19         //method 3
 20         Test(int &vara, char *& varb)
 21         {
 22             this->a = vara;
 23             this->b = varb;
 24         }   
 25         
 26         ~Test(){}
 27 }; 

I have here used simple fields int and char*,what will happen if I have many fields or complex types like struct ??

Thanks

Upvotes: 3

Views: 4605

Answers (7)

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 248219

They don't do the same thing.

Method 1 initializes the class members with the specified values.

Methods 2 and 3 first default-initializes the members (which for non-POD types means calling the default constructor), and then calls the assignment operator to assign a new value to them.

In other words, 2 and 3 will fail to compile if the class contains references, or if one of the members do not have a default constructor. It will also be slower for most non-POD types.

In other words, use the initializer list (method 1). That's what it's for. It is better from a correctness as well as a performance point of view.

Upvotes: 1

Vijay Mathew
Vijay Mathew

Reputation: 27204

The first method (using initializer list) is the preferred way to initialize member variables of a C++ class. Its advantage is that it lets you choose which constructor to use for each member. The problem with the second method is that the default constrictors of the member fields will already be called before the body of the constructor is entered. This is also the only method of invoking a base class constructor, when the base class does not has a default constructor. The other two constructors are same, method 3 being the least preferred from a stylistic perspective.

Upvotes: 2

Tyler McHenry
Tyler McHenry

Reputation: 76740

There is absolutely no difference between Methods 2 and 3. Within a member function (including constructors and destructors) a member variable x is synonymous with this->x. The only time this makes a difference is if there is another variable named x in a nearer scope. For example:

int Foo::memberFunc() {
  return x; // Returns member variable x. Same as return this->x.
}

int Foo::memberFunc(int x) {
  return x; // Returns the argument x. Need to say return this->x to return member x
}

Method 1 is normally the preferred way of initializing member variables because it makes it explicit that that is what you are doing.

In your case, it is also identical to methods 2 and 3, but in some cases it is not. In particular, if any of your member variables are constants, references, or objects without default constructors, then Method1 is the only way you can initialize them.

Another small difference of Method 1 is that if any of your member variables are objects, using Methods 2 or 3 they will be constructed with their default constructors first and then modified or assigned to int he constructor code, while with Method 1 you can create them with a constructor other than the default in the first place.

Upvotes: 3

John Millikin
John Millikin

Reputation: 200966

The first way, called "initialization lists", is the best. It is required for reference attributes, and for standard attributes is more efficient.

The second way will invoke the standard constructors for all attributes, and then use the assignment operator on each assigned attribute. It is slower, and potentially will break entirely if an attribute type does not support assignment.

The third way is exactly the same as the second, but needlessly verbose. Prefixing attribute access with this-> is poor style unless there is a local variable shadowing an attribute.


Unrelated to the question, there's no need to use references for basic types. You're adding additional overhead for pointer dereferences, and since the values are being assigned to non-references anyway, there's no point to it.

Upvotes: 3

Peter Cardona
Peter Cardona

Reputation: 2110

Probably not a HUGE difference in terms of performance, but in method 1, you're constructing a and b using a copy constructor. In method 2, you're constructing a and b automatically, THEN using the assignment operator. That could be slower for more complex types than int and char*.

Method 3 is exactly the same thing as method 2.

Upvotes: 4

Jaime Garcia
Jaime Garcia

Reputation: 7116

method 3 is usually used if you have something like

Test (int &a, char &b) 
{
    this->a = a;
    this->b = b;
}

in order to fully qualify that you're setting the class field a and b, it's basically the same as method 2.

Upvotes: 1

anon
anon

Reputation:

For the types you use, there will probably be no difference in performance. However for non-POD data (classes with constructors) the form:

Test(int &vara, char *& varb) : a(vara), b(varb){}

will be the most efficient. This is because non-POD data will be initialised whther you provide an initialisation list or not. The other forms, which use assignment, will take the hit for initialisation, and then another hit for assignment.

Upvotes: 15

Related Questions