Reputation: 141
It's a thing which I missed somehow, but I am surprised. Consider the following code example:
#include <iostream>
class A
{
int a;
public:
A(int a) : a(a) { std::cout << "Normal constructor called." << std::endl; }
A(const A& orig) : a(orig.a) { std::cout << "Copy constructor called." << std::endl; }
};
void testFunction1(const A arg) { std::cout << "testFunction1()" << std::endl; }
void testFunction2(const A& arg) { std::cout << "testFunction2()" << std::endl; }
int main()
{
testFunction1(A(2));
testFunction2(A(2));
return 0;
}
I expected the following result:
/* Normal constructor called. */
/* Copy constructor called. */
/* testFunction1() */
/* Normal constructor called. */
/* testFunction2() */
But I was wrong. The exact result was the following:
/* Normal constructor called. */
/* testFunction1() */
/* Normal constructor called. */
/* testFunction2() */
Why wasn't the copy constructor called when I passed A(2)
by value to testFunction1()
? Does it mean that there is no difference between passing an rvalue by value or reference in C++98? Is it an optimization? Is A(2)
and arg
totally the same object in testFunction1()
?
Upvotes: 2
Views: 251
Reputation: 73424
Is it an optimization?
Yes! It's called Copy Elision, where a copy can be elided (bypassed), if possible, depending on the compiler.
So in your case, the compiler understands that it can get away without calling the copy constructor, and does exactly this. Note that even if you used arg
, like for example calling a printing member function of A
, copy elision could still be employed by the compiler, for optimization purposes. In other words, not using arg
is not the cause of this behavior.
If you use an ancient compiler, or temper the settings of your current one, you will probably see the result you expected at the first place.
With c++17, copy elision would be guaranteed in this case, as Guillaume Racicot mentioned.
Upvotes: 3