首页 > 解决方案 > 为什么map emplace调用右值构造函数两次

问题描述

class twoMem {
    int _a;
    int _b;

    public:
    twoMem() { 
        std::cout << "default constructor" << std::endl; 
    }

    twoMem(int a, int b) :_a(a), _b(b) { 
        std::cout << "constructor called" <<   std::endl; 
    }

    twoMem(const twoMem& other) {
        std::cout << "copy constructor called" << std::endl;
        _a = other._a;
        _b = other._b;
    }

    twoMem(const twoMem&& other) {
        std::cout << "rvalue copy constructor called" << std::endl;
        _a = other._a;
        _b = other._b;
    }

    ~twoMem() {
        std::cout << "destructor called" << std::endl; 
    }
};

int main()
{
    std::map<std::string, twoMem> myMap{};
    myMap.emplace(std::make_pair("foo", twoMem{ 1, 2 }));
    return 0;
}

输出:

constructor called
rvalue copy constructor called
rvalue copy constructor called
destructor called
destructor called
destructor called

标签: c++11

解决方案


首先,make_pairtwoMem参数移动到pair<const char*, twoMem>它返回。其次,emplace()从那个移动到实际节点。

做了

myMap.emplace("foo", twoMem{ 1, 2 });

那么移动构造函数只被调用一次。这就是重点map::emplace

您可以通过这种方式实现零复制或移动构造函数:

myMap.emplace(std::piecewise_construct, std::make_tuple("foo"), std::make_tuple(1, 2));

虽然可以说这种治疗方法可能比疾病更糟,因为现在你正在构建和复制元组,这可能至少与复制一样昂贵twoMem


推荐阅读