To demonstrate my problem, consider this simple program that does not compile:
#include <boost/noncopyable.hpp>
#include <unordered_map>
class foo : boost::noncopyable { };
int main()
{
std::unordered_map<int, foo> m;
auto & element = m[0];
return 0;
}
Using the current version of boost (1.52), Visual Studio 2012 returns the error:
cannot access private member declared in class 'boost::noncopyable_::noncopyable.
The operator [] for std::unordered_map returns a reference to the element at the provided key, which at first glance seems like it should work — I’ve asked for a reference to the element, not a copy of it.
My understanding of the problem is this (which might be wrong, as I haven’t used C++ in a while). If the key is not found, unordered_map creates a new element and returns a reference to the new element. boost::noncopyable defines a (private) copy constructor but not a move constructor, and so a move constructor is not generated by the compiler. In its operator[], std::unordered_map makes use of std::move, but since boost::noncopyable doesn’t define a move constructor, it falls back to the copy constructor. Since the copy constructor is private, the compilation fails.
What prompted this post is that I’m trying to create an unordered_map of boost::signal2::signal, which inherits from boost::noncopyable. Short of hacking the boost library, is there a simple workaround I can do? Wrapping the signal in a unique_ptr is an option, but it seems to me I might be doing something wrong here.
Update:
I may have posted too soon! It appears impossible to add a subclass of boost::noncopyable to unordered_map. Insert, operator[], and emplace all use either a copy constructor (which is private), or a move operation (which doesn’t exist for boost::noncopyable). To me this seems a major limitation. Is it even possible to create an unordered_map that contains boost::noncopyable objects? I’m explicitly not trying to copy them — I want them to spend their entire lifespan inside the unordered_map.
It’s not impossible to use a subclass of
boost::noncopyablein anunordered_map, you simply have to define a move constructor for you type. C++ does not create a default move constructor if you’ve made your own copy construct (which is whatboost::noncopyabledoes). Also, if it did define default move constructor, it would try to call the parent’s copy constructor which is private. So you must define a move constructor that doesn’t try to callboost::noncopyable‘s copy constructor. For example this works fine: