【问题标题】:Can you use `std::remove_if` on a container of `std::unique_ptr`?你可以在 `std::unique_ptr` 的容器上使用 `std::remove_if` 吗?
【发布时间】:2011-12-07 12:04:07
【问题描述】:

给定一个std::vector<std::unique_ptr<SomeType> >,使用它是否合法 remove_if 就可以了吗?换句话说,给定这段代码:

std::vector<std::unique_ptr<SomeType> > v;
//  fill v, all entries point to a valid instance of SomeType...
v.erase( std::remove_if( v.begin(), v.end(), someCondition ), v.end() );

,我是否保证在擦除后仍然在 v 中的所有指针都是 有效的。我知道,鉴于直观的实现 std::remove_if,鉴于我看过的所有实现, 他们会。我想知道标准中是否有任何内容 这保证了它;即 std::remove_if 不允许复制 任何有效条目,而无需将副本重新复制到其最终版本中 地点。

(当然,我假设条件不复制。如果 条件的签名如下:

struct Condition
{
    bool operator()( std::unique_ptr<SomeType> ptr ) const;
};

,那么当然之后所有的指针都会失效 remove_if.)

【问题讨论】:

  • James Kanze 提问 - 一种非常罕见的现象!
  • unique_ptr 不可复制,因此如果您使用该谓词,您的代码将无法编译。
  • 为什么不呢? std::unique 不可复制但可移动。它可以移动到容器的末尾。
  • @KennyTM:但是问题中给出的谓词按值接受参数,因此需要一个复制构造函数。
  • @VJovic:不,他没有。他把那个谓词作为一个确实复制的例子。然后他对指针无效的说法不正确,auto_ptr 是这样,unique_ptr 不是这样(代码根本无法编译)。

标签: c++ c++11


【解决方案1】:

就像erase()resize() 一样,remove_if()移动 元素(可能通过交换),因此容器元素不需要是可复制的。 unique_ptr 没有什么特别之处,它只是另一种只能移动的类型。

正如您所指出的,谓词当然应该通过 const-reference 获取元素。同样,就像任何可移动类型一样。

【讨论】:

  • 标准中哪里有规定?更重要的是,它在哪里声明 remove_if 不会移动到某个临时位置,也许稍后会将值留在那里,因为它确定不需要将其放在其他地方?容器和那里的成员函数已被改写以反映移动语义,但我不知道在这方面描述 remove_if 的语言有任何变化。
  • @JamesKanze:请注意,“已删除”元素的状态未指定。当您擦除尾部序列或重新分配其中的元素时,您的指针最迟将被释放,但可能更早(即标准没有说明)。
  • @KerrekSB “已移除”元素的状态并不是让我担心的。这是未删除的元素的状态。假设remove_if 获取元素的副本以准备移动它,然后决定不必移动它。
  • @JamesKanze:它不会那样做。它只会移动元素。如果你没有复制构造函数并且移动构造函数不是noexcept,那么我认为它甚至不会编译,或者至少你必须承担出现异常的风险。 (这来自 17.6.3.5:分配器要求。)
【解决方案2】:

N3290 中的 25.3.8 谈到了删除功能:

要求:*first 的类型应满足 MoveAssignable 要求(表 22)。

注意:[ret,last) 范围内的每个元素,其中 ret 是返回的 值,具有有效但未指定的状态,因为算法可以 通过与之前的元素交换或移动来消除元素 原来在那个范围内。

这意味着它取决于您的谓词运算符。由于您的谓词不会创建副本,因此不会复制元素。

【讨论】:

  • §25.3.8/1 是对目标类型的约束,而不是对remove 的实现的约束。 §25.3.8/6 是我要找的。太糟糕了,这是一个注释,而不是规范。但它确实表明了意图。在发布之前,我应该阅读注释,而不仅仅是规范性文本。无论如何+1,如果没有人找到更明确的答案,我会认为这是最终的回应。
  • 我有 n3242。之后是否添加了§25.3.8/6?我的 /6 讨论了 remove_copy[_if]
  • 我认为该注释不正确。好在它不规范。 ;-) 算法不允许交换元素,因为元素不需要是可交换的。该算法只能使用移动赋值。
猜你喜欢
  • 2021-08-08
  • 1970-01-01
  • 2015-11-01
  • 2016-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 2011-09-14
相关资源
最近更新 更多