Here is a complete program:
#include <iostream>
using std::cout;
using std::endl;
using std::move;
int count {0}; // global for monitoring
class Triple {
public:
Triple() = default; // C++11 use default constructor despite other constructors being declared
Triple(Triple&&) = default;
Triple(const Triple& t) : // copy constructor
Triple(t.mX, t.mY, t.mZ) {
count++;
}
Triple(const int x, const int y, const int z) :
mX{ x }, mY{ y }, mZ{ z } {
}
const Triple& operator +=(const Triple& rhs) {
mX += rhs.mX;
mY += rhs.mY;
mZ += rhs.mZ;
return *this;
}
int x() const;
int y() const;
int z() const;
private:
int mX{ 0 }; // c++11 member initialization
int mY{ 0 };
int mZ{ 0 };
};
#if 0
inline Triple operator+(const Triple& lhs, const Triple& rhs) {
Triple left { lhs };
left += rhs;
return left;
}
#else
inline Triple operator+(Triple left, const Triple& rhs) {
left += rhs;
return left;
}
#endif
int main()
{
Triple a,b;
cout << "initial value of count is: " << count << endl;
auto result { a+b };
cout << "final value of count is: " << count << endl;
}
Of interest is the fact that the copy constructor has a side effect, and there are two versions of the operator+
to contemplate.
Case 1
inline Triple operator+(const Triple& lhs, const Triple& rhs) {
Triple left { lhs };
left += rhs;
return left;
}
Case 2
inline Triple operator+(Triple left, const Triple& rhs) {
left += rhs;
return left;
}
Visual Studio 2015 gives the same result for either, printing a result of 1
. However gcc 4.8.4 gives 2
for Case 1.
This summary of copy elision※ states “which isn't the function parameter” which makes me suppose that VS is wrong. Is that correct?
But, why are formal parameter names treated specially in this rule? Why isn't it exactly like any other local variable?
(I'm not saying that the optimizer would figure things out depending on calling conventions and in light of separate compilation of caller and call-ee, but merely why it's not allowed.)
Edit: if outputting 1
is correct, how does that fit with the elision rule?
Note ※: I found this text is copied from §12.8 paragraph 31 in the publicly available N3690.
operator+
), and all six print1
. – Bundmove
constructor as well. – Martyrize