I recently stumbled upon some strange behavior in my solution to an equation that made me ask myself if I really understood how semantics and RVO move together.
There are many related questions in this forum , and I also read many common explanations on this. But my problem seems pretty specific, so I hope someone helps me.
The nested structure is a bit complicated, but it breaks, at least until then:
struct Foo
{
Bar* Elements;
Foo(void) : Elements(nullptr)
{
cout << "Default-constructing Foo object " << this << endl;
}
Foo(Foo const& src) : Elements(nullptr)
{
cout << "Copying Foo object " << &src << " to new object " << this << endl;
if (src.Elements != nullptr)
{
Allocate();
copy (src.Elements, src.Elements + SIZE, Elements);
}
}
Foo(Foo&& src) : Elements(nullptr)
{
cout << "Moving Foo object " << &src << " into " << this << endl;
Swap(src);
}
~Foo(void)
{
cout << "Destructing Foo object " << this << endl;
Deallocate();
}
void Swap(Foo& src)
{
cout << "Swapping Foo objects " << this << " and " << &src << endl;
swap(Elements, src.Elements);
}
void Allocate(void)
{
Elements = new Bar[SIZE]();
}
void Deallocate(void)
{
delete[] Elements;
}
Foo& operator=(Foo rhs)
{
cout << "Assigning another Foo object to " << this << endl;
Swap(rhs);
return *this;
}
Foo& operator+=(Foo const& rhs)
{
cout << "Adding Foo object " << &rhs << " to " << this << endl;
cout << "Added Foo object" << endl;
return *this;
}
Foo operator+(Foo rhs) const
{
cout << "Summing Foo objects" << endl;
return rhs += *this;
}
static Foo Example(void)
{
Foo result;
cout << "Creating Foo example object " << &result << endl;
return result;
}
};
Now consider the following short program:
int main()
{
Foo a = Foo::Example();
cout << "Foo object 'a' is stored at " << &a << endl;
Foo b = a + a;
cout << "Foo object 'b' is stored at " << &b << endl;
}
These were my expectations before I ran this code:
- The method
Examplecreates an instance of a local object Foo, as a result of which the default ctor is called. Example Foo . , , - RVO.- ctor .
a Example. a + a, operator+ .- , .
operator+= *this .operator+= , return operator+.- , , . ,
b ( 2 3). a b , .
( , ) , 8 ( , ). :
01 Default-constructing Foo object 0x23fe20
02 Creating Foo example object 0x23fe20
03 Foo object 'a' is stored at 0x23fe20
04 Copying Foo object 0x23fe20 to new object 0x23fe40
05 Summing Foo objects
06 Adding Foo object 0x23fe20 to 0x23fe40
07 Added Foo object
08 Copying Foo object 0x23fe40 to new object 0x23fe30
09 Destructing Foo object 0x23fe40
10 Foo object 'b' is stored at 0x23fe30
11 Destructing Foo object 0x23fe30
12 Destructing Foo object 0x23fe20
operator+ :
Foo operator+(Foo rhs) const
{
cout << "Summing Foo objects" << endl;
rhs += *this;
return rhs;
}
:
01 Default-constructing Foo object 0x23fe20
02 Creating Foo example object 0x23fe20
03 Foo object 'a' is stored at 0x23fe20
04 Copying Foo object 0x23fe20 to new object 0x23fe40
05 Summing Foo objects
06 Adding Foo object 0x23fe20 to 0x23fe40
07 Added Foo object
08 Moving Foo object 0x23fe40 into 0x23fe30
09 Swapping Foo objects 0x23fe30 and 0x23fe40
10 Destructing Foo object 0x23fe40
11 Foo object 'b' is stored at 0x23fe30
12 Destructing Foo object 0x23fe30
13 Destructing Foo object 0x23fe20
, rhs x (, , return move(rhs += *this);) move ctor.
, -fno-elide-constructors :
01 Default-constructing Foo object 0x23fd30
02 Creating Foo example object 0x23fd30
03 Moving Foo object 0x23fd30 into 0x23fe40
04 Swapping Foo objects 0x23fe40 and 0x23fd30
05 Destructing Foo object 0x23fd30
06 Moving Foo object 0x23fe40 into 0x23fe10
07 Swapping Foo objects 0x23fe10 and 0x23fe40
08 Destructing Foo object 0x23fe40
09 Foo object 'a' is stored at 0x23fe10
10 Copying Foo object 0x23fe10 to new object 0x23fe30
11 Summing Foo objects
12 Adding Foo object 0x23fe10 to 0x23fe30
13 Added Foo object
14 Moving Foo object 0x23fe30 into 0x23fe40
15 Swapping Foo objects 0x23fe40 and 0x23fe30
16 Moving Foo object 0x23fe40 into 0x23fe20
17 Swapping Foo objects 0x23fe20 and 0x23fe40
18 Destructing Foo object 0x23fe40
19 Destructing Foo object 0x23fe30
20 Foo object 'b' is stored at 0x23fe20
21 Destructing Foo object 0x23fe20
22 Destructing Foo object 0x23fe10
, ,
. : - , 8 (, , , )? .
gcc mingw-w64 x86-64 v.4.9.2 -std=c++11 .
p.s. - , , OO- ; -)