I will compile the following code with the command g++ -std=c++11 t.cpp :
#include <vector> #include <cstring> //memcpy() class s { char *p; size_t size; public: s(){ size=10; p=new char[size]; } s(const s &other){ size=other.size; p=new char[size]; memcpy(p,other.p,other.size); } ~s(){ delete [] p; } }; int main() { std::vector<s> ss; ss.push_back(s()); }
This is gdb log:
Breakpoint 1, main () at t.cpp:23 23 ss.push_back(s()); s::s (this=0x7fffffffe370) at t.cpp:9 9 size=10; 10 p=new char[size]; 11 } std::vector<s, std::allocator<s> >::push_back(s&&) (this=0x7fffffffe350, __x=<unknown type in /tmp/a.out, CU 0x0, DIE 0x20d0>) at /usr/include/c++/4.9/bits/stl_vector.h:932 932 { emplace_back(std::move(__x)); } std::move<s&> (__t=...) at /usr/include/c++/4.9/bits/move.h:102 102 { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } std::vector<s, std::allocator<s> >::emplace_back<s>(s&&) (this=0x7fffffffe350) at /usr/include/c++/4.9/bits/vector.tcc:94 94 if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) 101 _M_emplace_back_aux(std::forward<_Args>(__args)...); 102 } s::~s (this=0x7fffffffe370, __in_chrg=<optimized out>) at t.cpp:17 17 ~s(){ delete [] p; } std::vector<s, std::allocator<s> >::~vector (this=0x7fffffffe350, __in_chrg=<optimized out>) at /usr/include/c++/4.9/bits/stl_vector.h:425
From the magazine I get the following impression:
- GCC ignores the copy constructor
s(const s &other) . GCC automatically creates a move constructor for class s , and then std::vector.push_back() calls the move constructor.
This article states
Thus, if the definition of class C does not explicitly declare a move assignment operator, one will be implicitly defaulted only if the following conditions are true:
My question here is that class s apparently has a user-declared destructor ~s() , which means that class s does not meet the fourth condition, and therefore GCC should not apply move to std::vector.push_back() . How does GCC behave like this?
The destructor ~s() is called two times: first immediately after the temporary s() was passed as the argument ss.push_back(s()); and moved , and the second after the destructor, std::vector<s> is called.
- Since this code does not comply with rule three , it is doomed to fail when the destructor
std::vector<s> called. The content pointed to by p in the s object is already deleted first ~s() . Therefore, the call to std::vector<s> ~s() destructor should be in error, like double free or corruption .
However, to my great surprise, somehow this program starts and finishes normally.
Question 1 : Why is the program not crashing? I was just lucky?
question 2 : according to gdb log, does this mean that the codes intended for the previous C ++ 11 meet the rule of three , but do not correspond to the rule of five , as this example, with a high probability it will fail when compiling in C ++ 11 executable files?
EDIT
This question was raised due to my misinterpretation of gdb messages like these:
std::vector<s, std::allocator<s> >::push_back(s&&) emplace_back(std::move(__x)); std::vector<s, std::allocator<s> >::emplace_back<s>(s&&)
which make me think that GCC is creating a move constructor. I just did as many experts told me, setting a breakpoint in s(const s &other) and noticed that the program stopped there. This discovery will nullify all my questions.
As each expert suggested, the facts are as follows: 1. GCC does not create a move constructor. 2. The existing copy constructor is called.
Thank you all for your help!