【发布时间】:2012-12-22 08:54:15
【问题描述】:
为了演示我的问题,考虑这个无法编译的简单程序:
#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 的运算符 [] 返回对所提供键处元素的引用,乍一看似乎应该可以工作——我要求的是对元素的引用,而不是它的副本.
我对这个问题的理解是(这可能是错误的,因为我有一段时间没有使用 C++)。如果未找到该键,unordered_map 将创建一个新元素并返回对新元素的引用。 boost::noncopyable 定义了一个(私有)复制构造函数,但没有定义一个移动构造函数,因此编译器不会生成移动构造函数。在它的 operator[] 中,std::unordered_map 使用了 std::move,但由于 boost::noncopyable 没有定义移动构造函数,它回退到复制构造函数。由于拷贝构造函数是私有的,所以编译失败。
促使这篇文章的原因是我试图创建一个 boost::signal2::signal 的 unordered_map,它继承自 boost::noncopyable。除了破解 boost 库,我能做一个简单的解决方法吗?将信号包装在 unique_ptr 中是一种选择,但在我看来,我可能在这里做错了什么。
更新:
我可能发布得太早了!似乎不可能将 boost::noncopyable 的子类添加到 unordered_map。 Insert、operator[] 和 emplace 都使用复制构造函数(私有)或移动操作(对于 boost::noncopyable 不存在)。对我来说,这似乎是一个主要限制。甚至可以创建一个包含 boost::noncopyable 对象的 unordered_map 吗?我明确不试图复制它们——我希望它们在 unordered_map 中度过他们的整个生命周期。
【问题讨论】:
-
在将项目移入哈希表的过程中,复制是您请求的操作的本质所固有的。执行
insert()也会遇到完全相同的问题。我不知道有人甚至可以拥有带有不可复制实体的map<>或unordered_map<>(就此而言,map<>的密钥)。如果不是这样,我有点想了解自己。emplace()能满足你的需求吗? -
你是对的。从 boost::noncopyable 继承时,似乎甚至无法将项目添加到 unordered_map。
-
查看
emplace()家族。它可能会做你正在寻找的东西。祝你好运。 -
我删除了我的答案,因为我认为这可能是一个库错误。标准说
operator[]只要求映射类型是默认可构造的,而不是复制或移动构造的。您可以有一个地图,您只需默认使用operator[]构造所有元素,然后再修改它们。 -
@WhozCraig 遗憾的是没有 :(。Emplace() 没有可操作的移动构造函数,尽管从概念上讲这正是我想要做的。我不想复制这些对象。我只是想要他们住在 unordered_map 中,但这似乎是不可能的。