'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 1:[1]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1