【问题标题】:map/unordered_map with non-movable, default constructible value typemap/unordered_map 具有不可移动的默认可构造值类型
【发布时间】:2015-02-18 23:22:46
【问题描述】:

更新:在 23.5.4.3 here 中,m[1] 版本应该是有效的

Update2:m[1] 正在使用 gcc4.9.1

具体来说,std::mutex。假设我想要一个std::unordered_map<int, std::mutex>。这可能吗?

如果mutex 或持有互斥锁的实习生std::pair 在某个级别上触发已删除的复制构造函数上的错误,我似乎无法将mutex 添加到map。

m.emplace(1);
m.emplace(1, {});
m[1];

全部编译失败。我真正想要的只是在map 内就地构建mutex。

我宁愿不使用std::unique_ptr<std::mutex>,但我知道这可能是我最好的选择。

添加:operator[] 的完整示例在 gcc 和 clang 下对我来说失败

#include <unordered_map>
#include <mutex>

int main() {
    std::unordered_map<int, std::mutex> m;
    m[1];

    return 0;
}

clang3.5 中最相关的错误部分

/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/stl_pair.h:126:35: error: call to deleted constructor of 'std::mutex'
        : first(std::forward<_U1>(__x)), second(__y) { }
                                         ^      ~~~
...

f.cpp:6:6: note: in instantiation of member function 'std::__detail::_Map_base<...>::operator[]' requested here
    m[1];
     ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/mutex:163:5: note: 'mutex' has been explicitly marked deleted here
    mutex(const mutex&) = delete;
    ^

来自 gcc 4.7.2

In file included from /usr/include/c++/4.7/utility:72:0,
                 from /usr/include/c++/4.7/unordered_map:38,
                 from f.cpp:1:
/usr/include/c++/4.7/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int; <template-parameter-2-2> = void; _T1 = int; _T2 = std::mutex]’:
/usr/include/c++/4.7/bits/stl_pair.h:273:72:   required from ‘constexpr std::pair<typename std::__decay_and_strip<_T1>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = std::mutex; typename std::__decay_and_strip<_T2>::__type = std::mutex; typename std::__decay_and_strip<_T1>::__type = int]’
/usr/include/c++/4.7/bits/hashtable_policy.h:463:24:   required from ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::operator[](_Key&&) [with _Key = int; _Pair = std::pair<const int, std::mutex>; _Hashtable = std::_Hashtable<int, std::pair<const int, std::mutex>, std::allocator<std::pair<const int, std::mutex> >, std::_Select1st<std::pair<const int, std::mutex> >, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>; std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type = std::mutex]’
f.cpp:6:8:   required from here
/usr/include/c++/4.7/bits/stl_pair.h:126:45: error: use of deleted function ‘std::mutex::mutex(const std::mutex&)’
In file included from f.cpp:2:0:
/usr/include/c++/4.7/mutex:163:5: error: declared here
In file included from /usr/include/c++/4.7/utility:72:0,
                 from /usr/include/c++/4.7/unordered_map:38,
                 from f.cpp:1:
/usr/include/c++/4.7/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<typename std::__decay_and_strip<_T1>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = std::mutex; typename std::__decay_and_strip<_T2>::__type = std::mutex; typename std::__decay_and_strip<_T1>::__type = int]’:
/usr/include/c++/4.7/bits/hashtable_policy.h:463:24:   required from ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::operator[](_Key&&) [with _Key = int; _Pair = std::pair<const int, std::mutex>; _Hashtable = std::_Hashtable<int, std::pair<const int, std::mutex>, std::allocator<std::pair<const int, std::mutex> >, std::_Select1st<std::pair<const int, std::mutex> >, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>; std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type = std::mutex]’
f.cpp:6:8:   required from here
/usr/include/c++/4.7/bits/stl_pair.h:273:72: error: use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = int; _T2 = std::mutex; std::pair<_T1, _T2> = std::pair<int, std::mutex>]’
/usr/include/c++/4.7/bits/stl_pair.h:120:17: note: ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = int; _T2 = std::mutex; std::pair<_T1, _T2> = std::pair<int, std::mutex>]’ is implicitly deleted because the default definition would be ill-formed:
/usr/include/c++/4.7/bits/stl_pair.h:120:17: error: use of deleted function ‘std::mutex::mutex(const std::mutex&)’
In file included from f.cpp:2:0:
/usr/include/c++/4.7/mutex:163:5: error: declared here

【问题讨论】:

标签: c++ c++11 stl move


【解决方案1】:

两个选项。

一个是你尝试的第三件事,m[1],应该编译。你遇到了什么错误?

第二种是将emplace与piecewise_construct构造函数一起使用:

m.emplace(std::piecewise_construct, std::make_tuple(1), std::tuple<>());

这个应该工作,虽然我认为很可能有一些标准库在那里不工作。

【讨论】:

  • 为什么要编译m[1]?在 unordered_map 上,如果缺少键 1,则必须创建默认构造的 std::mutex 并为其分配引用。在unordered_map 中构造一个新条目可能会导致您现有的存储桶被重新分配,并且该重新分配可能涉及将元素从一个存储桶移动到另一个存储桶。除非我们强制unordered_map 将每个元素存储在其自己的节点中,并使映射与指向所述节点的指针一起工作,否则这是不可避免的:这意味着每个人都在为不可移动对象的成本付出代价,而不仅仅是想要使用的人他们。
  • “除非我们强制 unordered_map 将每个元素存储在它自己的节点中”——这正是我们正在做的。 23.2.5/8 说:“重新散列使迭代器无效,更改元素之间的顺序,并更改哪些桶元素出现在其中,但不会使指针或对元素的引用无效。”不使引用无效的唯一方法是将每个元素保留在自己的节点中,并且只操作指针。进一步注意,要求只要求非常特定功能的元素可移动/可复制,而不是所有插入功能,如果重新散列可以移动它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-14
  • 1970-01-01
  • 2018-10-04
相关资源
最近更新 更多