为什么C ++ 11按值移动构造函数?

时间:2013-11-21 23:44:22

标签: c++ c++11

我认为以下示例与std::map::emplace()具有相同的结果,但它没有:

struct MoveTest {
    MoveTest():
        var(true)
    {
        cout << "ctor: " << static_cast<void*>(&var) << endl;
    }

    MoveTest(MoveTest&& mt):
        var(std::move(mt.var))
    {
        cout << "move ctor: " << static_cast<void*>(&var) << endl;
    }

    bool var;
};


int main() {
    map<int, MoveTest> mtest;
    mtest.insert(make_pair(1, MoveTest()));
    return 0;
}

输出:

ctor: 0x7fff12e4e19b
move ctor: 0x7fff12e4e194
move ctor: 0x25f3034

MoveTest::var在每次移动中都有不同的地址。它看起来不像是“ move ”。我的代码或理解有什么问题?

2 个答案:

答案 0 :(得分:5)

有关MoveTest为你定义它,有没有真正太多的举动构造函数(或赋值运算符)可以优化(或通常做的 - 一切能做的,只能是从源头去目的地复制)

当一个对象包含指向堆上分配的一堆外部存储器的指针时,移动主要是一个很大的胜利。在这种情况下,移动ctor /赋值运算符基本上可以执行浅拷贝(即,只是从移动的对象中抓取指针)而不是深拷贝(复制该指针引用的所有数据)。

例如:

class move_tst {
    int *buffer;
    static const int size = 1024 * 1024;
public:
    move_tst() {        
        buffer = new int[size];
        std::iota(buffer, buffer + size, 0);
    }

    move_tst(move_tst const &other) {
        buffer = new int[size];
        std::copy_n(other.buffer, size, buffer);
    }

#ifdef MOVE
    move_tst(move_tst &&other) {
        buffer = other.buffer;
        other.buffer = nullptr;
    }
#endif

    ~move_tst() { 
        delete [] buffer;
    }
};

警告:我在这里使用了new的原始调用和原始指针,因此没有其他任何内容涉及,我们不会(例如)通过智能指针获得移动语义。对于正常情况下的普通代码,你应该使用(原始指针或new的原始调用,我的意思)。

编辑:就std::move所做的而言,它实际上并没有进行移动 - 它只是表示您不再关心某个值,因此它有资格成为移动的来源,即使这会摧毁它的价值。

例如,对于上面的课程,您可以进行如下测试:

for (int i = 0; i < 1000; i++) {
    move_tst src;
    move_tst dst =src;
}       

...并将其与:

进行比较
for (int i = 0; i < 1000; i++) {
    move_tst src;
    move_tst dst = std::move(src);
}       

如果没有std::movedst将被创建为src的副本,但使用std::move,它将能够从{{src移动1}}到dst

答案 1 :(得分:1)

您的日志只是告诉您使用默认构造函数

创建临时MoveTest实例
MoveTest()
然后将

复制到其他位置的对象

make_pair(1, MoveTest())

并再次复制到地图对象内的某处

mtest.insert(make_pair(1, MoveTest()));

三个不同的MoveTest实例有三个构造函数调用,每个实例都有自己的地址。正如已经很好地解释的那样,构造函数是移动构造函数还是旧式复制构造函数并不重要。

您是否期望将某些副本优化掉?在构造函数中使用非平凡的代码变得不可能;特别是,阅读&amp; var 是避免捷径的好理由。

相关问题