我使用命令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());
}
这是gdb
日志:
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
从日志中,我的印象如下:
s(const s &other)
。 GCC会自动为move
创建class s
构造函数,然后std::vector.push_back()
调用move
构造函数。
因此,如果C类的定义没有明确说明 声明一个移动赋值运算符,一个将隐式 仅在满足以下所有条件时才声明为默认值 满足:
我的问题是,class s
显然有一个用户声明的析构函数~s()
,意味着class s
不符合第四个条件,因此GCC不应强制执行move
std::vector.push_back()
。海湾合作委员会如何表现?
析构函数~s()
被调用两次:首先将临时s()
作为参数传递给ss.push_back(s());
并移动,然后第二次std::vector<s>
的析构函数被称为。
std::vector<s>
的析构函数时注定会崩溃。对象p
中s
指向的内容已被第一个~s()
删除。因此,调用std::vector<s>
的{{1}}析构函数必须崩溃,并显示~s()
之类的错误。然而,令我惊讶的是,这个程序以某种方式运行并正常终止。
问题1 :为什么程序不崩溃?我只是幸运吗?
问题2 :根据double free or corruption
日志,是否意味着为先前的C ++ 11会议设计的代码gdb
但未满足rule of five,例如这个例子,当它们被编译成C ++ 11可执行文件时很可能会崩溃吗?
修改:
由于我误解了rule of three
这样的消息,提出了这个问题:
gdb
这让我认为GCC创建了一个移动构造函数。我只是按照这些专家告诉我的那样做了 - 在std::vector<s, std::allocator<s> >::push_back(s&&)
emplace_back(std::move(__x));
std::vector<s, std::allocator<s> >::emplace_back<s>(s&&)
中设置一个断点,并注意到程序确实停在那里。这一发现使我的所有问题无效。
正如这里的每位专家所说,事实是: 1. GCC不会创建任何移动构造函数。 2.调用现有的复制构造函数。
谢谢大家的帮助!
答案 0 :(得分:8)
GCC忽略了复制构造函数(const s&amp; other)。
它可能会这样做,作为复制省略优化。
GCC自动为类s创建移动构造函数,然后调用移动构造函数的std :: vector.push_back()。
没有。不生成移动构造函数。
我的问题是,类s显然有一个用户声明的析构函数~s(),这意味着类s不符合第四个条件
正确。该类也不符合第一个条件(用户声明的复制构造函数)。
海湾合作委员会似乎表现得如此。没有移动建设或任务。GCC如何表现?
析构函数~s()被调用两次
在您显示的gdb日志中,我只看到一个s::~s
被调用的实例。
问题1:为什么程序不会崩溃?我只是幸运吗?
我会认为你不走运。似乎push_back
没有使用复制赋值运算符,因此没有发生双重释放的条件。
问题2:根据gdb日志,它是否意味着为先前的C ++ 11设计的代码符合三条规则而不符合五条规则,如此示例...
此示例不符合三条规则,因此这似乎不是您要求的示例。
在编译为C ++ 11可执行文件时很可能会崩溃吗?
没有。只要代码遵循三条规则,就可以安全地复制对象。遵循五的规则只是为了使对象可移动(避免复制)。
答案 1 :(得分:3)
#include <vector>
#include <cstring> //memcpy()
#include <iostream>
class s
{
char *p;
size_t size;
public:
s(){
std::cout<<this<<"\tdefault constructor\n";
size=10;
p=new char[size];
}
s(const s &other){
std::cout<<this<<"\tcopy constructor\n";
size=other.size;
p=new char[size];
memcpy(p,other.p,other.size);
}
~s(){
std::cout<<this<<"\tdestructor\n";
delete [] p;
}
};
int main()
{
std::vector<s> ss;
ss.push_back(s());
}
对我来说,我正在被毁坏2个不同的对象:
0x7fffc879aa50默认构造函数
0x1668c40复制构造函数
0x7fffc879aa50析构函数
0x1668c40析构函数
问题1:为什么程序不会崩溃?我只是幸运吗?
没有双重合作。
编译:
g ++ -O3 --std = c ++ 11 file2.cpp -o file2.out
G ++ 4.7.3
答案 2 :(得分:3)