提问人:DDG 提问时间:9/9/2023 最后编辑:DDG 更新时间:9/10/2023 访问量:73
为什么propagate_on_container_move_assignment不适用于容器的复制构造函数
Why is propagate_on_container_move_assignment not applicable for copy constructors of a container
问:
我已经阅读了一些关于propagate_on_container_move_assignment的旧帖子来了解它是如何工作的,但仍然无法理解一些更精细的问题。根据我的理解,移动构造函数以简单的方式工作(移动构造分配器以及任何内部状态),但移动赋值运算符需要处理分配器何时可以传播。
以下问题中的答案:两个链接提供了有关分配器传播如何工作以及为什么需要它的一些背景
从上面的链接复制 -
容器移动分配操作员必须处理三个单独的 可能性:
- propagate_on_container_move_assignment是真的。
- propagate_on_container_move_assignment 是错误的,并且 LHS 和 RHS 的分配器比较相等。
- propagate_on_container_move_assignment 是错误的,并且 LHS 和 RHS 的分配器比较不相等。
然而,我理解前两种情况,对于第三种情况,“propagate_on_container_move_assignment是假的,来自 lhs 和 rhs 的分配器比较不相等。我不明白这怎么不是移动构造函数的问题。在移动分配的案例 3 中,我们最终会复制数据,因为我们不能拥有 rhs 分配器的内存。在移动构造过程中,我们假设我们始终可以拥有内存,并且只需移动构造分配器以及内部状态。如果这在移动构造函数中是可能的,那么我们是否不能在移动分配中做类似的事情 - 移动分配器并移动分配内部状态。
在我看来,如果情况 3 对于移动分配是正确的,那么这意味着我们在没有“传播”检查的情况下实现的移动构造函数将格式不正确。
请帮助我理解这个概念。最好提供一个示例,对于移动分配,由于分配器不支持传播,我们选择了第 3 种情况(分配器不支持 pocma = std::true_type 应该有正当理由)但移动构造函数有效?
谢谢
答:
C++98 不要求分配器是可分配的(实际上有些分配器不提供)。为了向后兼容,库不能使用赋值运算符,除非分配器说可以这样做。operator=
如果为 false,则并不意味着分配器“移动不安全”。这意味着分配器的作者已确定使用该分配器的容器不应因移动分配而更改其分配器。 以这种方式显式设计,因此当容器用作其分配器时,对象的分配器在对象的生存期内无法更改;对象的创建者对容器如何分配内存拥有唯一和绝对的控制权。propagate_on_container_move_assignment
std::pmr::polymorphic_allocator
std::pmr::polymorphic_allocator
由于此设计决策,移动分配运算符必须考虑以下情况:LHS 保留其原始分配器,但该分配器与 RHS 的分配器不相等,这意味着 LHS 分配器无法解除分配 RHS 分配器分配的内存。这意味着,例如,在移动赋值运算符的情况下,LHS 不能简单地从 RHS 中“窃取”缓冲区,因为结果将是 LHS 拥有 LHS 的分配器不知道如何解除分配的内存。相反,在这种情况下,移动分配将退化为元素移动分配。std::vector
在移动构造期间不会出现此问题,因为分配器始终在移动构造时传播。没有可以更改此行为的自定义点。因此,新对象从旧对象获取其分配器,因此,该分配器始终知道如何从新对象现在拥有所有权的旧对象中释放缓冲区。propagate_on_container_move_construction
在复制构造过程中也不会出现这种情况,因为复制构造函数从不采用源对象的内存,因此它不需要担心新对象的分配器是否可以释放任何采用的内存。首先,复制构造函数确定新对象将使用的分配器;然后,它使用该分配器为新对象中的所有元素分配内存。显然,同一个分配器稍后将知道如何释放该内存。
评论