I compile the following code using 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 log, I am in the following impression:
- GCC ignores copy constructor
s(const s &other)
. -
GCC automatically creates a
move
constructor forclass s
and thenstd::vector.push_back()
calls thatmove
constructor.This article states
Thus, if the definition of class C doesn't explicitly declare a move assignment operator, one will be implicitly declared as defaulted only if all of the following conditions are met:
My question here is that
class s
apparently has a user-declared destructor~s()
, meaningclass s
does not meet the forth condition and thus GCC should not enforcemove
onstd::vector.push_back()
. How does GCC behaves so? -
Destructor
~s()
is called two times: first immediately after temporarys()
has been passed as argument toss.push_back(s());
and moved, and second after the destructor ofstd::vector<s>
is called. - Because this code does not meet rule of three, it is doomed to crash when the destructor of
std::vector<s>
is called. The content pointed to byp
in objects
is already deleted by the first~s()
. Therefore,std::vector<s>
destructor calling~s()
must crash with error likedouble free or corruption
.
However, much to my surprise, somehow this program runs and terminates normally.
question 1: Why the program does not crash? Am I simply lucky?
question 2: According to gdb
log, does it mean that codes designed for prior C++11 meeting rule of three
but not meeting rule of five, like this example, are very likely to crash when they are compiled to C++11 executables?
Aucun commentaire:
Enregistrer un commentaire