Insert in unordered map calls constructor

无人久伴 提交于 2021-01-28 02:52:45

问题


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 my unordered_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 deleted 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!