gpt4 book ai didi

c++ - 使用不可复制(但可 move )键 move 分配 map 时出错

转载 作者:可可西里 更新时间:2023-11-01 17:50:05 28 4
gpt4 key购买 nike

为什么这不起作用:

#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 的默认 move 构造函数尝试使用 std::unique_ptr 的复制构造函数.我假设 map 赋值运算符使用新 map 内容对旧 map 内容的 move 赋值,并且 std::swap不能这样做,因为它需要保持旧内容完好无损,所以它只是交换内部数据指针,所以它避免了问题。

(至少能够) move 分配的必要性可能来自 problemsallocator_traits<M::allocator_type>::propagate_on_container_move_assignment在 C++11 中,但我的印象是在 C++14 中,整个事情都是固定的。我不确定为什么 STL 会选择 move 赋值元素,而不是仅仅在 move 赋值运算符中的容器之间交换数据指针。

以上所有内容都没有解释为什么 move map 中包含的对的 move 分配失败 - 恕我直言,它不应该。

顺便说一句:g++ -v :

gcc version 4.9.2 (Ubuntu 4.9.2-0ubuntu1~14.04) 

最佳答案

对我来说,这看起来像是 C++ 标准规范的根本失败。该规范在“不要重复自己”方面走得太远,以至于变得不可读和模棱两可(恕我直言)。

如果您进一步阅读表格Allocator-aware container requirements,同一行说(对于 a = rv ):

Requires: If allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is false, T is MoveInsertable into X and MoveAssignable. All existing elements of a are either move assigned to or destroyed. post: a shall be equal to the value that rv had before this assignment.

我想每个人都会同意std::map<std::unique_ptr<char>, std::unique_ptr<int>>是一个分配器感知容器。那么问题就变成了:它的 move 赋值运算符有什么要求?

如果我们只看分配器感知容器要求,那么MoveInsertableMoveAssignable只有在 allocator_traits<allocator_type>::propagate_on_container_move_assignment::value 时才需要是false .这是一个比 容器要求 表中规定的要求更弱的要求,该表规定所有 元素必须是 MoveAssignable不管分配器的属性如何。那么分配器感知容器是否也必须满足更严格的容器要求?

让我们将其展开为标准应该说的话,如果它不是那么努力地不重复自己的话。

实现需要什么?

如果allocator_traits<allocator_type>::propagate_on_container_move_assignment::valuetrue那么内存资源的所有所有权都可以在 move 分配期间从 rhs 转移到 lhs。这意味着 map move 赋值只能做 O(1) 指针来完成 move 赋值(当内存所有权可以转移时)。指针旋转不需要对指针指向的对象进行任何操作。

这是 map 的 libc++ 实现分配时 allocator_traits<allocator_type>::propagate_on_container_move_assignment::valuetrue :

https://github.com/llvm-mirror/libcxx/blob/master/include/__tree#L1531-L1551

可以看到绝对没有要求需要放在key_type上或 value_type .

我们应该人为地对这些类型提出要求吗?

这样做的目的是什么?它会帮助还是伤害 std::map 的客户? ?

我个人认为,对不需要的客户类型提出要求只会让客户感到沮丧。

我还认为,C++ 标准的当前规范风格非常复杂,以至于即使是专家也无法就规范的内容达成一致。这并不是因为专家是白痴。这是因为制定一个正确的、明确的规范(在这个规模上)确实是一个非常困难的问题。

最后,我认为当出现规范冲突时,意图是(或应该是)分配器感知容器要求取代容器要求。

最后一个并发症:在 C++11 中:

allocator_traits<allocator<T>>::propagate_on_container_move_assignment{} is false_type

在 C++14 中:

allocator_traits<allocator<T>>::propagate_on_container_move_assignment{} is true_type

所以 libstdc++ 行为符合 C++11,而 libc++ 行为符合 C++14。 LWG issue 2103进行了此更改。

关于c++ - 使用不可复制(但可 move )键 move 分配 map 时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36475497/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com