- #1
- 15,940
- 5,848
- TL;DR Summary
- A constructor doesn't seem to be invoked when it should be.
I mentioned in another thread that I've been playing with a C++ class for 3D vectors, to review overloaded operators, constructors, etc. All those functions display output so I can follow which ones get called, and when. The class generates a serial number for each vector so I can tell them apart.
I've been puzzled by something. To illustrate it, here's a trimmed-down version of the class that contains only the operations needed for this demonstration.
First, here's a
and its output:
Vectors #1, #2 and #3 are
Vector #4 is the local variable
This all seems reasonable to me.
Now, let's combine the declaration of
Based on my (possibly faulty) memory of how C++ compilers are supposed to handle this, I expected that this would bypass
Output:
Indeed,
What is vector #3?
If it's
If it's the local
If the compiler is doing some optimization, they why is it happening only in the second program and not the first one?
I've been puzzled by something. To illustrate it, here's a trimmed-down version of the class that contains only the operations needed for this demonstration.
C++:
class ThreeVector
{
private:
double x, y, z;
int serialNum; // unique for each ThreeVector instance
static int numVectors; // counts the number of ThreeVectors constructed
public:
ThreeVector (); // default constructor
ThreeVector (double, double, double);
ThreeVector (const ThreeVector&); // copy constructor
~ThreeVector ();
const ThreeVector operator+ (const ThreeVector&) const;
ThreeVector& operator= (const ThreeVector&);
friend ostream& operator<< (ostream& out, const ThreeVector& v);
};
int ThreeVector::numVectors = 0;
ThreeVector::ThreeVector ()
{
x = 0; y = 0; z = 0;
numVectors++;
serialNum = numVectors;
cout << "-- Default-constructed vector #" << serialNum
<< " containing " << *this << "." << endl;
}
ThreeVector::ThreeVector (double x0, double y0, double z0)
{
x = x0; y = y0; z = z0;
numVectors++;
serialNum = numVectors;
cout << "-- Constructed vector #" << serialNum << " containing "
<< *this << "." << endl;
}
ThreeVector::ThreeVector (const ThreeVector& original)
{
x = original.x; y = original.y; z = original.z;
numVectors++;
serialNum = numVectors;
cout << "-- Copy-constructed vector #" << serialNum << " containing "
<< *this << "." << endl;
}
ThreeVector::~ThreeVector ()
{
cout << "-- Destructed vector #" << serialNum << " containing "
<< *this << "." << endl;
}
const ThreeVector ThreeVector::operator+ (const ThreeVector& rhs) const
{
ThreeVector sum;
sum.x = x + rhs.x; sum.y = y + rhs.y; sum.z = z + rhs.z;
cout << "-- " << *this << " + " << rhs
<< " = " << sum << "." << endl;
cout << "Return from operator+..." << endl;
return sum;
}
ThreeVector& ThreeVector::operator= (const ThreeVector& rhs)
{
x = rhs.x;
y = rhs.y;
z = rhs.z;
cout << "-- Assigned " << *this << " to vector #" << serialNum
<< "." << endl;
return *this;
}
ostream& operator<< (ostream& out, const ThreeVector& v)
{
out << "(" << v.x << ", " << v.y << ", " << v.z << ")";
return out;
}
main()
function that works as I expected:
C++:
int main ()
{
cout << "Declare a and b..." << endl;
ThreeVector a(1, 2, 3), b(4, 5, 6);
cout << "Declare c..." << endl;
ThreeVector c;
cout << "Add c = a + b..." << endl;
c = a + b;
cout << "Return from main()..." << endl;
return 0;
}
Code:
Declare a and b...
-- Constructed vector #1 containing (1, 2, 3).
-- Constructed vector #2 containing (4, 5, 6).
Declare c...
-- Default-constructed vector #3 containing (0, 0, 0).
Add c = a + b...
-- Default-constructed vector #4 containing (0, 0, 0).
-- (1, 2, 3) + (4, 5, 6) = (5, 7, 9).
Return from operator+...
-- Assigned (5, 7, 9) to vector #3.
-- Destructed vector #4 containing (5, 7, 9).
Return from main()...
-- Destructed vector #3 containing (5, 7, 9).
-- Destructed vector #2 containing (4, 5, 6).
-- Destructed vector #1 containing (1, 2, 3).
a
, b
, and c
in main()
. They are destructed at the end of main()
. Vector #4 is the local variable
sum
in operator+()
. It is destructed when that function finishes, after its value is assigned (copied) to c
in main()
.This all seems reasonable to me.
Now, let's combine the declaration of
c
with the addition of a
and b
:
C++:
int main ()
{
cout << "Declare a and b..." << endl;
ThreeVector a(1, 2, 3), b(4, 5, 6);
cout << "Declare c and add c = a + b..." << endl;
ThreeVector c = a + b;
cout << "Return from main()..." << endl;
return 0;
}
operator=()
and use the copy-constructor to construct c.Output:
Code:
Declare a and b...
-- Constructed vector #1 containing (1, 2, 3).
-- Constructed vector #2 containing (4, 5, 6).
Declare c and add c = a + b...
-- Default-constructed vector #3 containing (0, 0, 0).
-- (1, 2, 3) + (4, 5, 6) = (5, 7, 9).
Return from operator+...
Return from main()...
-- Destructed vector #3 containing (5, 7, 9).
-- Destructed vector #2 containing (4, 5, 6).
-- Destructed vector #1 containing (1, 2, 3).
operator=()
was not used, but neither was the copy-constructor!What is vector #3?
If it's
c
in main()
, then why is there no vector #4 for the local sum
in operator+()
?If it's the local
sum
in operator+()
, then how does c
in main()
get constructed? Is there another constructor that I've overlooked?If the compiler is doing some optimization, they why is it happening only in the second program and not the first one?