插入无序映射调用构造函数

Insert in unordered map calls constructor

为了避免元素重复,我正在构建一个 class 来保存元素并提供对它们的访问。

我的元素(DynLibrary)可移动但不可复制

class DynLibrary
{
    public:
        DynLibrary() : _handle(nullptr) {}
        DynLibrary(const std::string& path) { DynLibrary::open(path); }
        DynLibrary(const DynLibrary&) = delete;
        DynLibrary(DynLibrary&&) = default;
        ~DynLibrary() { DynLibrary::close(); }
    ...
}

这些对象分配在 unordered_map 中,哪个键是生成它们的路径。 我就是这样分配的

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;
};

然而,当调用 DynAllocator::library 时,我得到以下输出:

@Emplace
close 0x1dfd1e0 // DynLibrary destructor
@Return

这意味着插入的对象已经以某种方式被复制,并且副本的析构函数刚刚使我的对象无效(使用我的处理程序调用 dlclose

请注意,我知道如何使用指针/智能指针 (std::unique_ptr) 来做到这一点,但我想不惜一切代价避免使用它们!

Which means that the object which is inserted has somehow been copied and the destructor of the copy just invalidated my object

不,那不是那个意思。 DynLibrary 有一个 deleted 复制构造函数,因此如果该构造函数是通过重载决议以某种方式选择的,则代码将无法编译。

_handles.emplace(f, DynLibrary(f));

上面这行发生的事情是您正在创建一个临时 DynLibrary 对象,然后 将构造的 移动到 unordered_map 中。如果您希望避免这种移动构造,请改用 std::piecewise_construct

_handles.emplace(std::piecewise_construct,
                 std::forward_as_tuple(f),
                 std::forward_as_tuple(f));

现在您直接在 unordered_map 中构建 DynLibrary 对象并绕过临时对象的创建。


如T.C。 ,在这种情况下不需要分段构造构造函数,因为DynLibrary有一个非explicit转换构造函数。您可以使用

实现与上述相同的效果
_handles.emplace(f, f);