【发布时间】:2016-07-28 07:04:03
【问题描述】:
为什么这不起作用:
#include <memory>
#include <map>
std::map<std::unique_ptr<char>, std::unique_ptr<int>> foo();
std::map<std::unique_ptr<char>, std::unique_ptr<int>> barmap;
int main(){
barmap=foo();
return 0;
}
虽然这样做:
#include <memory>
#include <map>
std::map<std::unique_ptr<char>, std::unique_ptr<int>> foo();
std::map<std::unique_ptr<char>, std::unique_ptr<int>> barmap;
int main(){
std::map<std::unique_ptr<char>, std::unique_ptr<int>> tmp(foo());
using std::swap;
swap(barmap, tmp);
return 0;
}
这与映射中的键类型不可复制的事实有关(std::map 需要吗?)。使用g++ -std=c++14编译时的相关错误行:
/usr/include/c++/4.9/ext/new_allocator.h:120:4: error: use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = const std::unique_ptr<char>; _T2 = std::unique_ptr<int>]’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^
In file included from /usr/include/c++/4.9/bits/stl_algobase.h:64:0,
from /usr/include/c++/4.9/memory:62,
from pairMove.cpp:1:
/usr/include/c++/4.9/bits/stl_pair.h:128:17: note: ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = const std::unique_ptr<char>; _T2 = std::unique_ptr<int>]’ is implicitly deleted because the default definition would be ill-formed:
constexpr pair(pair&&) = default;
^
/usr/include/c++/4.9/bits/stl_pair.h:128:17: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = char; _Dp = std::default_delete<char>]’
In file included from /usr/include/c++/4.9/memory:81:0,
from pairMove.cpp:1:
/usr/include/c++/4.9/bits/unique_ptr.h:356:7: note: declared here
unique_ptr(const unique_ptr&) = delete;
完整的错误信息可见at ideone。
在我看来,std::pair 的默认移动构造函数尝试使用 std::unique_ptr 的复制构造函数。我假设地图赋值运算符使用新地图内容的移动分配而不是旧地图内容,而std::swap 不能这样做,因为它需要保持旧内容完整,所以它只是交换内部数据指针,因此它避免了问题。
移动分配的必要性(至少能够)可能来自 C++11 中的 problems 和 allocator_traits<M::allocator_type>::propagate_on_container_move_assignment,但我的印象是在 C++14 中整个事情都已修复。我不确定为什么 STL 会选择移动赋值元素,而不是仅仅在移动赋值运算符中的容器之间交换数据指针。
以上所有内容都不能解释为什么移动地图中包含的对的移动分配失败 - 恕我直言,它不应该。
顺便说一句:g++ -v:
gcc version 4.9.2 (Ubuntu 4.9.2-0ubuntu1~14.04)
【问题讨论】:
-
嗯,我认为你的情况有所改变。您说第二个代码块有效,但随后您继续显示它的编译器错误。第一个代码块中也没有
tmp。第二个示例中也没有定义MyPtr。 -
@NathanOliver 对不起,我的错。两个代码实际上都有错误 - 现在已修复。 ideone.com 的错误实际上来自一个略有不同但相当于第一个块的代码。
-
这两个代码显然都无法编译,因为 foo 没有定义,但如果我走这么远尝试链接它,那么我的问题已经解决了。我省略了
foo的定义,因为我不想让编译器有机会优化太多并消除问题。 -
我通读了 C++14 中的 23.2.1,我认为第一个代码是否应该工作,但这是一个相当复杂的部分,所以我可能忽略了一些东西
-
代码有地图的右值引用,而不是对
标签: c++ c++14 move-semantics stdmap