Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any consequences from using *this to initialise a class?

In a small game I'm writing, I have a class Weapon with two constructors, one which takes in some parameters to produce a custom weapon, and one that grabs a default one (the CHAIN_GUN):

Weapon::Weapon (void) {     // Standard weapon     *this = getWeapon(CHAIN_GUN);     return; } 

Question: Are there any negative consequences from using *this and operator= to initialise a class?

like image 744
KKOrange Avatar asked Jun 03 '14 05:06

KKOrange


People also ask

Should you use the this pointer in the constructor?

Some people feel you should not use the this pointer in a constructor because the object is not fully formed yet. However you can use this in the constructor (in the { body } and even in the initialization list) if you are careful.

How do you initialize a class member in C++?

There are two ways to initialize a class object: Using a parenthesized expression list. The compiler calls the constructor of the class using this list as the constructor's argument list. Using a single initialization value and the = operator.

Are class members zero initialized?

zero-initialization – Applied to static and thread-local variables before any other initialization. If T is scalar (arithmetic, pointer, enum), it is initialized from 0 ; if it's a class type, all base classes and data members are zero-initialized; if it's an array, each element is zero-initialized.

Why constructors are efficient instead of a function Init () defined by the user to initialize the data members of an object?

Why constructors are efficient instead of a function init() defined by the user to initialize the data members of an object? Explanation: We cannot use init() because as mentioned in options that user may forget to initialize the members which will lead to a segmentation fault.


2 Answers

Imagine that someone asked you to draw a painting... would you;

  • first draw your default (1st) (that familiar smilie face you like so much),
  • then draw what that someone asked for (2nd),
  • only to draw the same thing one more time, but on the canvas containing your default,
  • and then burn the 2nd painting?

This post will try to explain why this simile is relevant.


WHY IS IT A BAD IDEA?

I've never seen a default-constructor implemented with the use of the assignment-operator, and honestly it's not something that I'd recommend, nor support during a code review.

The major problem with such code is that we are, by definition, constructing two objects (instead of one) and calling a member-function, meaning that we construct all our members two times, and later having to copy/move initialize all members by calling the assignment operator.

It's unintuitive that upon requesting construction of 1 object, we construct 2 objects, only to later copy the values from the 2nd to the 1st and discard the 2nd.

Conclusion: Don't do it.

( Note: In a case where Weapon has base-classes it will be even worse )

( Note: Another potential danger is that the factory function accidentially uses the default-constructor, resulting in an infinite recursion not caught during compilation, as noted by @Ratchet Freat )


PROPOSED SOLUTION

In your specific case you are far better off using a default-argument in your constructor, as in the below example.

class Weapon { public:   Weapon(WeaponType w_type = CHAIN_GUN);   ... } 

Weapon w1;             // w_type = CHAIN_GUN Weapon w2 (KNOWLEDGE); // the most powerful weapon 

( Note: An alternative to the above would be to use a delegating constructor, available in C++11 )

like image 190
Filip Roséen - refp Avatar answered Oct 14 '22 12:10

Filip Roséen - refp


Using the assignment operator to implement a constructor is rarely a good idea. In your case, for example, you could just use a default parameter:

Weapon::Weapon(GunType g = CHAIN_GUN) : // Initialize members based on g { } 

In other cases, you might use a delegating constructor (with C++11 or later):

Weapon::Weapon(GunType g) : // Initialize members based on g { }  Weapon::Weapon() : Weapon(CHAIN_GUN) // Delegate to other constructor { } 
like image 21
Vaughn Cato Avatar answered Oct 14 '22 14:10

Vaughn Cato