繁体   English   中英

std :: remove_if是否会调用析构函数?

[英]Does std::remove_if call the destructor?

我正在使用std::remove_if将选择的std::vector元素移动到末尾,以便我可以将它们复制到另一个向量然后擦除范围:

using ElemPtr = std::shared_ptr<Elem>;
auto iter = std::remove_if(source.begin(),source.end(), [&](const ElemPtr& e){ /* ... */ });
dest.insert(dest.end(),iter,source.end());
source.erase(iter,source.end());

发生的事情是,在调用std::remove_if ,要删除的值会调用它们的析构函数(即它们被设置为null)。 我最终只是复制了一堆空指针,这不是很好。

像cppreference.com这样的资源没有提到这种行为,所以我想知道这是否是编译器错误?

我正在使用gcc 5.2.0。

std::remove_if 动的元素被删除到最后。 取而代之的是,它的动作被删除到前部元件; 尾部的内容未指定。

在此过程中,谓词所说的应该被删除的一些元素可能会被其他元素覆盖(确切地说,从其中分配)。 对于一个shared_ptr的元素,这意味着它可以很好地破坏底层对象。

你似乎在寻找的是std::partition 它的行为与您期望std::remove_if的行为方式完全相同。

这不是一个错误。 事实上,他们并没有被称为破坏者,他们只是被感动了。 在调用容器的erase之前,不会调用它们的dtor。

cppreference.com提到,

通过移动(通过移动分配)范围中的元素来完成移除,使得不被移除的元素出现在范围的开头。 保留的元素的相对顺序被保留,容器的物理大小不变。 指向新逻辑结束和范围的物理结束之间的元素的迭代器仍然是可解除引用的,但元素本身具有未指定的值(根据MoveAssignable后置条件) 调用remove之后通常会调用容器的erase方法,该方法会擦除未指定的值并减小容器的物理大小以匹配其新的逻辑大小。

std::remove_if移动分配迭代器值符合给定元谓词(如果它们最初出现满足给定元谓词至少一个迭代值后)。 不会召唤任何析构函数。

可能实现std::remove_if

template< typename ForwardIt, typename UnaryPredicate >
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p) {
    first = std::find_if(first, last, p);
    if (first != last)
        for (ForwardIt i = first; ++i != last;)
            if (!p(*i))
                *first++ = std::move(*i); // Move assignment, no destructors called
    return first;
}

资料来源cppreference.com

插图( 擦除删除成语

代码 [ Wandbox ]:

#include <algorithm>
#include <iostream>
#include <vector>

struct A {
    constexpr A(int a) noexcept : m_a(a) {}
    constexpr A(const A&) noexcept = default;
    constexpr A(A&&) noexcept = default;
    ~A() noexcept {
        std::cout << "Destruction: " << m_a << std::endl;
    }
    A& operator=(const A& a) noexcept {
        std::cout << "Copy assignment: " << a.m_a << std::endl;
        m_a = a.m_a;
        return *this;
    }
    A& operator=(A&& a) noexcept {
        std::cout << "Move assignment: " << a.m_a << std::endl;
        m_a = a.m_a;
        return *this;
    }

    int m_a;
};


int main() {
    std::vector< A > v = { 1, 2, 5, 4, 5, 5 };
    std::cout << "BEGIN REMOVE" << std::endl;
    auto end = std::remove_if(v.begin(), v.end(), [](const A& a) noexcept { return 5 == a.m_a; });
    std::cout << "BEGIN ERASE" << std::endl;
    v.erase(end, v.end());
    std::cout << "END" << std::endl;
    return 0;
}

输出

Destruction: 5
Destruction: 5
Destruction: 4
Destruction: 5
Destruction: 2
Destruction: 1
BEGIN REMOVE
Move assignment: 4
BEGIN ERASE
Destruction: 4 // Could be garbage as well (unspecified, but valid, state)
Destruction: 5
Destruction: 5
END
Destruction: 1
Destruction: 2
Destruction: 4

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM