c++dictionarytry-catchemplace

emplace and try_emplace with copy constructor


I have an issue with emplace and try_emplace as they always use the copy constructors when moving an object in.

#include <iostream>
#include <unordered_map>
#include <map>

using namespace std;

class Too {
public:
     Too(int x, int y):x_(x), y_(y) {
        cout << "init " << x_  << endl;
    }
    Too(const Too& too):x_(too.x_+1), y_(too.y_+1) {
        cout << "Copy happen: x = " << x_ << endl;
     }
    ~Too() {
        cout << "delete too " << x_ << endl;
    }
private:
    int x_, y_;
};



std::map<int, Too> v;


int main()
{
    v.emplace(100, Too{ 100,23 });

    v.try_emplace(12, 12, 13);

    Too t = Too(10, 11);
    v.try_emplace(11, std::move(t));
}


output init 100 Copy happen: x = 101 delete too 100 init 12 init 10 Copy happen: x = 11 delete too 10 delete too 101 delete too 12 delete too 11


As you can see, only v.try_emplace(12, 12, 13) do not use the copy constructor. both v.emplace(100, Too{ 100,23 }) and v.try_emplace(11, std::move(t)) invoke the copy constructor.

So how can it be even when I use std::move(t)?

Any suggestion would be highly appreciated.

Thanks,


Solution

  • Since you've provided a copy constructor for your class, the move constructor Too::Too(Too&&) will not be implicitly generated by the compiler.

    Moreover, when there is no move constructor available for a class, the copy constructor can be used.


    For using the move constructor you have to explicitly provide an appropriate user-defined move constructor Too::Too(Too&&), then you will get the desired result.

    You can add the move constructor either by adding Too(Too&&) = default; or writing your own move constructor which will do the initialization in the constructor initializer list.