问题
In order to avoid duplication of elements, I'm building a class that holds elements and provide an acces to them.
My elements (DynLibrary
) are movable but not copyable
class DynLibrary
{
public:
DynLibrary() : _handle(nullptr) {}
DynLibrary(const std::string& path) { DynLibrary::open(path); }
DynLibrary(const DynLibrary&) = delete;
DynLibrary(DynLibrary&&) = default;
~DynLibrary() { DynLibrary::close(); }
...
}
Those object are allocated in an unordered_map
which key is the path that generated them.
I'm allocation them that way
class DynAllocator
{
public:
DynLibrary& library(const std::string& f)
{
if (_handles.find(f) == _handles.end())
{
std::cout << "@Emplace" << std::endl;
_handles.emplace(f, DynLibrary(f));
}
std::cout << "@Return" << std::endl;
return _handles.at(f);
}
private:
std::unordered_map<std::string, DynLibrary> _handles;
};
However when calling DynAllocator::library
I get the following output:
@Emplace
close 0x1dfd1e0 // DynLibrary destructor
@Return
Which means that the object which is inserted has somehow been copied and the destructor of the copy just invalidated my object (calling dlclose
with my handler)
- Is my movable but not copyable approach of
DynLibrary
ok ? - How can I insert an instance of
DynLibrary
if myunordered_map
without copy ?
Please note that I know how to do that using pointers / smart pointers (std::unique_ptr
) but that i'd like to avoid them at all cost !
回答1:
Which means that the object which is inserted has somehow been copied and the destructor of the copy just invalidated my object
No, that's not what that means. DynLibrary
has a delete
d copy constructor, so the code would not compile if that constructor were somehow chosen through overload resolution.
_handles.emplace(f, DynLibrary(f));
What's happening on the line above is you're creating a temporary DynLibrary
object which is then move constructed into the unordered_map
. If you wish to avoid this move construction, use std::piecewise_construct instead.
_handles.emplace(std::piecewise_construct,
std::forward_as_tuple(f),
std::forward_as_tuple(f));
Now you're directly constructing the DynLibrary
object within the unordered_map
and bypassing creation of the temporary.
As T.C. comments, the piecewise construction constructor is not necessary in this case because DynLibrary
has a non-explicit
converting constructor. You can achieve the same effect as above with
_handles.emplace(f, f);
来源:https://stackoverflow.com/questions/29927882/insert-in-unordered-map-calls-constructor