Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing class using { * this }

Tags:

c++

c++11

It was suggested by a team member that using an intializer like this:

return Demo{ *this };

was better than:

return Demo(*this);

Assuming a simple class like this:

class Demo {
public:
    int value1;
    Demo(){}
    Demo(Demo& demo) {
        this->value1 = demo.value1;
    }
    Demo Clone() {
        return Demo{ *this };
    }
};

I admit to having not seen the { *this } syntax before, and couldn't find a reference that explained it well enough that I understood how the two options differed. Is there a performance benefit, a syntax choice, or something more?

like image 234
WiredPrairie Avatar asked Dec 20 '13 22:12

WiredPrairie


People also ask

How do you initialize a class?

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.

Why do we use __ init __?

The __init__ function is called every time an object is created from a class. The __init__ method lets the class initialize the object's attributes and serves no other purpose. It is only used within classes.

What is class initialization in Python?

__init__ method "__init__" is a reseved method in python classes. It is called as a constructor in object oriented terminology. This method is called when an object is created from a class and it allows the class to initialize the attributes of the class.


1 Answers

Your colleague is missing a trick with "uniform initialization", there is no need for the type-name when it is known. E.g. when creating a return value. Clone could be defined as:

Demo Clone() {
    return {*this};
}

This will call the Demo copy constructor as needed. Whether you think this is better or not, is up to you.

In GOTW 1 Sutter states as a guideline:

Guideline: Prefer to use initialization with { }, such as vector v = { 1, 2, 3, 4 }; or auto v = vector{ 1, 2, 3, 4 };, because it’s more consistent, more correct, and avoids having to know about old-style pitfalls at all. In single-argument cases where you prefer to see only the = sign, such as int i = 42; and auto x = anything; omitting the braces is fine. …

In particular, using braces can avoid confusion with:

Demo d();      //function declaration, but looks like it might construct a Demo
Demo d{};      //constructs a Demo, as you'd expect

The brace syntax will use a constructor that takes an initializer list first, if one exists. Otherwise it will use a normal constructor. It also prevents the chance of the vexing parse listed above.

There is also different behaviour when using copy initialization. With the standard way

Demo d = x;

The compiler has the option to convert x to a Demo if necessary and then move/copy the converted r-value into w. Something similar to Demo d(Demo(x)); meaning that more than one constructor is called.

Demo d = {x};

This is equivalent to Demo d{x} and guarantees that only one constructor will be called. With both assignments above explicit constructors are cannot be used.

As mentioned in the comments, there are some pitfalls. With classes that take an initializer_list and have "normal" constructors can cause confusion.

vector<int> v{5};       // vector containing one element of '5'
vector<int> v(5);       // vector containing five elements.
like image 51
Steve Avatar answered Oct 03 '22 19:10

Steve