你能在存储 `std::unique_ptr` 的容器上使用 `std::remove_if` 吗?

21

给定一个类型为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() );

在使用 erase 后,在 vector v 中的所有指针是否仍然有效?我知道根据std::remove_if 的直观实现以及我查看过的所有实现,它们将是有效的。但我想知道标准中是否有任何保证;即 std::remove_if 不允许复制任何有效条目,而是需要将复制重新复制到其最终位置。

(当然,我假设条件不会复制。如果条件具有类似以下签名的形式:

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

当使用remove_if函数时,如果该容器使用指针指向其元素,那么在执行remove_if后所有指针都将无效。


10
詹姆斯·康泽提问是非常罕见的现象! - Nawaz
3
unique_ptr 不能进行拷贝构造,因此如果你使用了该谓词,你的代码将无法编译通过。 - interjay
1
为什么不呢?std::unique是可移动但不可复制的。它可以被移动到容器的末尾。 - ali_bahoo
3
但是问题中给定的谓词采用按值传递的参数,因此需要一个复制构造函数。 - interjay
2
@VJovic:不,他没有。他举了一个复制的谓词作为例子。然后他发表了一个关于指针失效的错误陈述,这在auto_ptr中是正确的,但在unique_ptr中不是(代码根本无法编译)。 - interjay
显示剩余4条评论
2个回答

8

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

正如您指出的那样,谓词当然应该通过const引用接受元素。再次强调,对于任何可移动类型都适用。


这在标准中哪里说明了?更重要的是,它在哪里说明remove_if不会移动到某个临时位置,可能稍后会将该值留在那里,因为它确定不需要将其放在其他地方?容器及其成员函数已经重新表述以反映移动语义,但我不知道有关描述remove_if的语言方面是否有任何变化。 - James Kanze
@JamesKanze:请注意,“已删除”元素的状态是未指定的。当您擦除尾序列或重新分配其中的元素时,您的指针将在最迟释放,但可能更早(即标准没有说明)。 - Kerrek SB
@KerrekSB,“已删除”元素的状态并不是我担心的问题。我担心的是那些未被删除的元素的状态。假设“remove_if”在移动元素之前先复制了一份,然后决定不必移动它。 - James Kanze
1
@JamesKanze:它不会这样做。它只会移动元素。如果您没有复制构造函数,并且移动构造函数不是“noexcept”,那么它甚至不会编译,我认为,或者至少您必须承担异常的风险。(这遵循于17.6.3.5:分配器要求。) - Kerrek SB

3

在N3290中的25.3.8中提到remove函数:

要求:*first的类型需满足可移动赋值操作(表22)的要求。

并且

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

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


§25.3.8/1是针对目标类型的约束,而非“remove”方法的实现。§25.3.8/6是我在寻找的内容。遗憾的是它只是一条注释,而不是规范性的内容。但这确实使意图清晰明了。在发帖前,我应该阅读注释,而不仅仅是规范性的内容。无论如何都会+1,并且如果没有人找到更具体的信息,我将考虑它为最终回复。 - James Kanze
我有n3242。在此之后添加§25.3.8/6吗?我的/6讨论了remove_copy[_if] - kennytm
2
我认为那个注释是不正确的。好在它不是规范性的。;-) 算法不允许交换元素,因为这些元素不要求可交换。算法只能使用移动赋值。 - Howard Hinnant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接