Link to home
Start Free TrialLog in
Avatar of Subrat (C++ windows/Linux)
Subrat (C++ windows/Linux)Flag for India

asked on

Why move constructor in the below sample code is not gets called?

#include <iostream>
class A {
public:
    int ii = 20;
    A(int i = 200) {
        std::cout << "A() \n";
        ii = i;
    }
    A(const A& obj) {
        std::cout << "Copy Constructor\n";
    }
    A(A&& obj) noexcept {
        std::cout << "A(A&&)\n";
    }
};

void fun(A i) {
    std::cout << "Fun \n" << i.ii << std::endl;
}

int main(int argc, const char * argv[]) {
    fun(A(12)); // Why this is not calling move constructor.
    return 0;
}

Open in new window

Avatar of ste5an
ste5an
Flag of Germany image

I'm not a C++ guy, but a ctor is only called when you instantiate an object. You only use the public (static) method. Something like

int main(int argc, const char * argv[]) {
    A* obj = new  A(12);  
    return 0;
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Zoppo
Zoppo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Subrat (C++ windows/Linux)

ASKER

Better if you can give some more example to understand this concept.
Sorry, I was too busy some days to give some samples.

The copy elision is just a smart compiler functionality which eliminates unneeded copy- and even move-operations where possible.

Consider this example:
class T {};

foo( T param ) { /*do something */ }

int main()
{
 T test;
 foo( t );
}

Open in new window

What's happening here is something like this:

1. main is called
2. test is instantiated on the stack
3. param is instantiated on the stack
4. test is copied to param
5. foo is called
6. param is destroyed and removed from the stack
7. foo is returns
8. test is destroyed and removed from the stack
9. main returns

Now change it to use a temporary instance instead:
int main()
{
 foo( T() );
}

Open in new window

What you expect is that only the copying is replaced by a move operation, somehow like this:

1. main is called
2. a temporary instance of T is instantiated on the stack (lets call it temp)
3. param is instantiated on the stack
4. temp is moved to param
5. foo is called
6. temp is destroyed and removed from the stack
7. foo is returns
8. param is destroyed and removed from the stack
9. main returns

Here in fact only 4. is different, which is probably better, but you have to consider moving even costs something because all instances of a class need to be copied anyway, only deep-copying of dynamically allocated data can be avoided - for example if you have a struct which contains a member like 'int numbers[1000000]' even a move operation has to copy 1 million ints.

What's obious is that there are two instances of T used (including two dtor/ctor-calls) allthough there's for sure only one instance at a time which owns data.

To improve this copy elision is used: a compiler knows the temporary instance isn't intended to be used in main at all so there's simply no need to create two instances including all the needed functionality fo creation/copying/moving/destruction at all.

So instead of the shown operations the compiler treats it this way:

1. main is called
2. param is instantiated on the stack
3. foo is called
4. foo is returns
5. param is destroyed and removed from the stack
6. main returns

This way the instance 'param' is instanced in-place where it is used, so the variable is 'passed' (which in this context isn't really the correct word) at zero cost.

A similar optimization technique is used with return, it's the return value optimization (RVO).

Consider this example:
T foo()
{
 T test;
 return test;
}

Open in new window

In such a case the compiler even detects there's no reason to create a second instance in the calling function which retrieves a copy of the local instance test, so the test instance can be seen as instanced in-place in the calling function and directly used in foo.

This is great, this way the compilers are able to improve performance of lots of code significantly, even old code can be improved by this a lot without need to change a single line of code!

I hope this helps,

ZOPPO
Typo: replace t with test in Call to foo
Excuse me ... I'm sure there are more typos, but I hope beside this the code-blocks are ok :o)