struct B
{
virtual ~B() = default;
virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B
{
//deep copy
std::string value;
bool valid = true;
char* data = nullptr;
int size = 0;
D() { /*std::cout << "D::D\n"; */}
~D() {/* std::cout << "D::~D\n"; */}
D(const std::string& value,int size) {
this->value = value;
data = new char[size];
this->size = size;
}
D(const D& other) {
if (!this->data) {
data = new char[other.size];
}
else if (this->size < other.size) {
delete data;
data = new char[size];
}
else {
memset(this->data,0,this->size);
}
memmove(data, other.data, other.size * sizeof(char));
this->size = other.size;
this->value = other.value;
}
D(D&& other) {
//move and reset other
if (this->data) {
delete data;
data = nullptr;
}
this->value = std::move(other.value);
this->data = other.data;
this->size = other.size;
other.size = 0;
other.data = nullptr;
other.valid = false;
}
}
含有堆上数据(data 和 value)的类D实现了移动构造函数 D(D&& other) 后,与std::vector 的 push_back 和 emplace_back 配合使用,特定条件下可以提高效率。见代码和注释。
//假设对象 d 已经在别处构造好了, 并且放到 ds 以后不再使用
//!Good, 利用了D的移动构造函数
{
D&& rd = std::move(d);
ds.push_back(std::move(rd));
}
{
D&& rd = std::move(d);
ds.emplace_back(std::move(rd));
}
//!Bad,调用了拷贝构造函数
{
ds.push_back(rd);
}
{
ds.emplace_back(rd);
}
测试代码和结果:
enum CODE {
PUSH,
PUSH_MOVE,
EMPLACE,
EMPLACE_MOVE,
};
std::map<CODE, std::string> codes;
std::string fiillen(std::string& str,int len) {
while (str.length() < len) {
str += " ";
}
return str;
}
/*输出为
PUSH 13855
PUSH_MOVE 2930
EMPLACE 9733
EMPLACE_MOVE 3759
*/
int test() {
codes[PUSH] = "PUSH";
codes[PUSH_MOVE] = "PUSH_MOVE";
codes[EMPLACE] = "EMPLACE";
codes[EMPLACE_MOVE] = "EMPLACE_MOVE";
INT64 time = 0;
INT64 bytes = 1000;
INT64 count = 100;
auto test = [&](int code) {
/*
在外部构造 d,避免对 ds 操作的干扰
*/
D d("", bytes);
std::vector<D> ds;
auto t1 = steady_clock::now();
for (int i = 0; i < 10; i++) {
switch (code)
{
case PUSH:
ds.push_back(d);
break;
case EMPLACE:
ds.emplace_back(d);
break;
case PUSH_MOVE: {
D&& rd = std::move(d);
ds.push_back(std::move(rd));
}
break;
case EMPLACE_MOVE: {
D&& rd = std::move(d);
ds.emplace_back(std::move(rd));
}
break;
default:
break;
}
}
auto t2 = steady_clock::now();
auto tt = duration_cast<nanoseconds>(t2 - t1);
time += tt.count();
};
for (int code = 0; code < 4; code++) {
time = 0;
for (int i = 0; i < count; i++) {
test(code);
}
std::cout << fiillen(codes[(CODE)code],20) << " " << time / count << std::endl;
}
return 0;
}
从测试结果来看移动构造由于节省了很多拷贝 data 的时间, push_back 和 emplace_back 得到了速度上的优化,其他 std 容器类比一下应该具有同样特性。
需要注意的一点是以下代码不能获得这种优化,在 emplace_back(push_back)时,调用的还是拷贝构造函数。
D&& rd = std::move(d);
ds.emplace_back(rd);