Subrat (C++ windows/Linux)
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;
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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:
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:
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/de struction 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:
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
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 );
}
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() );
}
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/de
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;
}
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
ASKER
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)
Open in new window