boost :: noncopyable的unordered_map无法从operator []返回引用

时间:2012-12-22 08:54:15

标签: c++ boost

为了演示我的问题,请考虑这个不编译的简单程序:

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

使用当前版本的boost(1.52),Visual Studio 2012返回错误: cannot access private member declared in class 'boost::noncopyable_::noncopyable

std :: unordered_map的operator []返回对提供的键元素的引用,乍一看似乎应该有效 - 我已经要求引用元素,而不是它的副本

我对这个问题的理解是这个(这可能是错的,因为我有一段时间没有使用过C ++)。如果未找到该键,则unordered_map将创建一个新元素并返回对该新元素的引用。 boost :: noncopyable定义(私有)复制构造函数,但不定义移动构造函数,因此编译器不会生成移动构造函数。在其operator []中,std :: unordered_map使用std :: move,但由于boost :: noncopyable没有定义移动构造函数,因此它会回退到复制构造函数。由于复制构造函数是私有的,因此编译失败。

提示这篇文章的是我正在尝试创建一个boost :: signal2 :: signal的unordered_map,它继承自boost :: noncopyable。如果没有黑客攻击库,我可以做一个简单的解决方法吗?将信号包装在unique_ptr中是一种选择,但在我看来,我可能在这里做错了。

更新

我可能发布太快了!似乎无法将boost :: noncopyable的子类添加到unordered_map。 Insert,operator []和emplace都使用复制构造函数(私有)或移动操作(对于boost :: noncopyable不存在)。对我来说这似乎是一个主要的限制。甚至可以创建一个包含boost :: noncopyable对象的unordered_map吗?我明确地试图复制它们 - 我希望它们将整个生命周期都花在unordered_map中。

2 个答案:

答案 0 :(得分:6)

boost::noncopyable中使用unordered_map的子类并非不可能,您只需为您键入一个移动构造函数即可。如果您已经创建了自己的复制构造(这是boost::noncopyable的作用),C ++不会创建默认的移动构造函数。此外,如果它确实定义了默认移动构造函数,它将尝试调用父项的私有复制构造函数。因此,您必须定义一个不会尝试调用boost::noncopyable的复制构造函数的移动构造函数。例如,这很好用:

#include <boost/noncopyable.hpp>
#include <unordered_map>

struct foo : public boost::noncopyable
{
    foo() = default;
    foo(foo&&) {}
};

int main()
{
    std::unordered_map<int, foo> m;
    auto & element = m[0];

    return 0;
}

答案 1 :(得分:1)

这可能不是你想要的,但我想我会把它丢在那里。需要注意的一件事是来自second的返回对的emplace()值,表示第二次调用引入新成员,也不复制现有成员。

同样,我不知道这是否更接近你想要的,但值得一试。我可能做错了,因为我不像其他人那样过分熟悉C ++ 11标准库。很抱歉,如果是这样。

最后,请注意这是试图解决OP使用operator []()进行插入+访问的请求。相反,它试图简单地将boost::noncopyable推导构造成unordered_map<>。要访问您,可能需要使用以下内容和初始find()的组合来确定标记最初是否存在。

总之...

#include <boost/noncopyable.hpp>
#include <iostream>
#include <unordered_map>

class Foo : public boost::noncopyable
{
public:
    Foo(int value) : value(value) {};

    void setValue(int value) { this->value = value; }
    int getValue() const { return value; }

private:
    int value;
};


int main(int argc, char *argv[])
{
    typedef std::unordered_map<std::string, Foo> MyMap;
    MyMap mymap;

    // throw ("test".1) into the map
    auto p = mymap.emplace("test", 1);
    auto q = mymap.emplace("test", 2); // should not overwrite the first.

    // dump content
    cout << p.first->second.getValue() << '(' << p.second << ')' << ' '
         << q.first->second.getValue() << '(' << q.second << ')' << endl;

    // modify through the second returned iterator/bool pair.
    q.first->second.setValue(3);

    // dump again, see if p was also updated.
    cout << p.first->second.getValue() << '(' << p.second << ')' << ' '
         << q.first->second.getValue() << '(' << q.second << ')' << endl;

    return 0;
}

<强>输出

1(1) 1(0)
3(1) 3(0)