1

I am trying to get a map of an int to a class. For some reason when I run the code it doesn't compile. The code is below.

#include <iostream>
#include <mutex>
#include <map>

 
using namespace std;

class test {
private:
    mutex thismutex;
public:
    test(){
        
    };
    ~test(){

    };
};

int main() {
    map<int,test> testmap;
    testmap[1] = test();

    return 0;
}

If you remove the mutex from the class the code compiles perfectly fine. How can I fix this?

jujumumu
  • 350
  • 4
  • 12
  • Because of the `mutex` member, `test` is not assignable, so an attempt to assign to `testmap[1]` fails to compile. `testmap.emplace(1, {})` would probably work (I'm too lazy to test). Alternatively, you can provide `test::operator=` – Igor Tandetnik Nov 09 '20 at 00:56
  • You could make it a `map>`, and then `testmap[1] = make_unique();`. – Don Hatch Nov 09 '20 at 01:21

1 Answers1

2

A std::mutex is not copyable or movable. This means that your class, which has a mutex as a member, does not have a default copy constructor. Which makes its use somewhat limited with most containers, including a map. That's the reason for your compilation error. You're trying to create a new entry in a map in a way that requires a copy to be made, and the class cannot be copied.

You could define an explicit copy constructor and an assignment operator, and implement them in whatever way is meaningful for your test class. That's one option.

Or, it is possible to gingerly create non-copyable objects directly in the std::map. You can't use the most common ways to copy or move new values into the map. The trick is to avoid copying them as part of the process; but constructing them in place:

map<int,test> testmap;
test &new_test=testmap[1];

This is one situation where the [] operator overload is convenient, but only as long as the class has a default constructor. You can also use try_emplace from C++17:

map<int,test> testmap;

test &new_test=testmap.try_emplace(1).first->second;

This creates a new entry in the std::map, whose value, your test object; which also gets constructed in place. See a textbook that covers C++17, or cppreference for more information. If a class does not have a default constructor and its explicit constructor requires any parameters, you can shove them into try_emplace, to get forwarded to the constructor.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148