【问题标题】:Why does `std::pmr::polymorphic_allocator` not propagate on container move?为什么`std::pmr::polymorphic_allocator`不会在容器移动时传播?
【发布时间】:2017-12-18 16:17:56
【问题描述】:

来自http://en.cppreference.com/w/cpp/memory/polymorphic_allocator

polymorphic_allocator 不会在容器复制分配、移动分配或交换上传播。因此,polymorphic_allocator-using 容器的移动分配可能会抛出,并且交换两个分配器不相等的 polymorphic_allocator-using 容器会导致未定义的行为。

为什么我会想要这种行为?这似乎不仅在交换上引入了无缘无故的未定义行为,而且更重要的是,就我的目的而言,这意味着 std::pmr::vector 实际上是一种不可移动分配的类型。我的意思是,它是可移动分配的,但这几乎可以保证是低效的。

std::vector<int> v = {1, 2, 3};
std::vector<int> w;
w = std::move(v);  // nocopy, nothrow

std::pmr::monotonic_buffer_resource mr(1000);
std::pmr::vector<int> v( {1, 2, 3}, &mr );
std::pmr::vector<int> w;
w = std::move(v);  // yescopy, yesthrow

我的猜测是,这是处理所有权问题的原始尝试。在我上面的第二个示例中,v 持有对 mr 的引用,但 v 实际上并不拥有 mr。允许非拥有引用在整个系统中未经检查地传播往往会引入许多微妙的错误。因此,设计者没有发明一个拥有分配器,而是决定不传播mr的引用。这最终产生了不好的影响,例如移动分配向量现在会复制其数据;但是你最终不会得到那么多指向内存资源的悬空指针。 (一些是的,但没有那么多。)


附:我已经看到您可以通过提前设置分配器来避免复制/抛出,如下所示:

std::pmr::monotonic_buffer_resource mr(1000);
std::pmr::vector<int> v( {1, 2, 3}, &mr );
std::pmr::vector<int> w(v.get_allocator());
w = std::move(v);  // nocopy, nothrow

【问题讨论】:

  • 几乎可以保证效率低下” 标准从不保证任何容器移动分配操作都是恒定时间。它在要求中说得对:移动分配是线性的。移动 construction 是常数时间,而不是赋值。一般来说,人们不会经常进入现有容器。因此,这没什么大不了的。此外,移动操作不会复制元素。它只会移动它们。所以这和说没有移动分配是不一样的。

标签: c++ c++17 allocator


【解决方案1】:

allocator_traits&lt;&gt;::propagate_on_container_copy/move_assignment/swap 是分配器的静态 属性。根据设计,多态分配器的属性在运行时定义。有些多态分配器可以传播给其他分配器,有些则不能。

因此,在编译时不可能知道这些属性。所以 PMR 分配器必须在编译时假设最坏的情况:没有传播。

让我们以你的例子为例,有一个改动:

std::pmr::monotonic_buffer_resource mr(1000);
std::pmr::vector<int> v( {1, 2, 3}, &mr );
std::pmr::vector<int> w;
auto a1 = w.get_allocator();
w = std::move(v);
assert(w.get_allocator() == a1);

C++ 标准要求 this 没有断言。赋值不会移动容器的allocator;这就是容器分配与 C++ 中的分配器一起工作的方式。

因此,目标容器的分配器要么可以处理源容器的内存,要么不能。如果不能,则目标容器必须分配内存并从源中复制/移动对象。

移动赋值运算符是否为noexcept 是运算符的静态属性。而且由于 PMR 直到运行时才知道它们是否可以传播存储,因此容器必须将其移动赋值运算符指定为抛出移动赋值。

在运行时,它实际上可以决定是否可以传播。如果可能,那么它会走更有效的路径。

【讨论】:

  • @Nicol_Bolas 我对“一些多态分配器可以传播给其他人,而有些不能”这句话有点困惑。我的意思是 polymorphic_allocator 只是持有一个指向 memory_resource 的指针以用于分配。我唯一的猜测是,这是指 polymorphic_allocator 使用的内存资源仅用于分配 std::pmr::vector? 的特定实例的情况。这是正确的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-19
  • 2014-04-25
  • 2014-01-13
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
  • 2016-10-26
相关资源
最近更新 更多