2

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 Answer 1

3

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);
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you, then std::piecewise_construct approch works well. Still I'm wondering why would anyone want to call the destructor is called on the temporary ?
@Amxx: If you have a unique ownership resource, you're supposed to make the moved-from object not destroy the resource in it's destructor.
@Amxx You constructed a temporary which was then used as the source object for a move construction within the unordered_map. Once that's complete, the temporary needs to be destroyed, regardless of whether it was moved from or not.
@Amxx Puppy has a very good point in his comment. Depending on what type the _handle data member is, the defaulted move constructor may not be sufficient. For instance, if it is a void *, you'll need to define the move constructor and set the source object's _handle to nullptr to avoid it being destroyed in the destructor of the source object.
Do you actually need piecewise_construct for the the code shown in the OP? The pair( U1&& x, U2&& y ); constructor should handle it. (Of course, if DynLibrary(const std::string& path) were explicit, you'd need it...)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.