如何获得满足谓词的向量中唯一ptrs的子集?

时间:2017-03-11 19:56:27

标签: c++ c++11 iteration unique-ptr predicate

我有std::unique_ptr<Foo>个对象的向量。我想获得符合某些条件的所有矢量项的集合。 我看到std函数,但它们似乎都测试谓词(并返回bool)或返回单个元素。

是否有内置机制来获取作为向量子集的集合?如果没有,有没有办法构造一个迭代器,根据任意谓词测试项目(以识别满足我条件的项目)和返回符合该谓词的所有项目的机制?

3 个答案:

答案 0 :(得分:6)

警告,因为你有一个unique_ptr的向量,那些元素只能移动,即一旦你有了子集,原始向量将不再相同

破坏性最小的方法是使用std::stable_partition将矢量分成两组,同时将所有内容保存在同一个矢量中:

auto sep = std::stable_partition(vec.begin(), vec.end(), [](const auto& foo) {
    return foo->is_good();
});
// the part `vec.begin() .. sep` contains all "good" foos.
// the part `sep .. vec.end()` contains all "bad" foos.

如果订单不重要,use std::partition instead。用法是一样的。

如果要将不良foos拆分为另一个向量,可以使用std::copy_if + std::make_move_iterator将对象移出。请注意,这将在任何地方留下漏洞。使用std::remove进行清理。

decltype(vec) bad_vec;
std::copy_if(std::make_move_iterator(vec.begin()),
             std::make_move_iterator(vec.end()),
             std::back_inserter(bad_vec),
             [](const auto& p) { return !p->is_good(); });
auto new_end = std::remove(vec.begin(), vec.end(), nullptr);
vec.erase(new_end, vec.end());

如果你不再关心&#34;坏&#34;对象,使用std::remove_if

auto new_end = std::remove_if(vec.begin(), vec.end(), [](const auto& foo) {
    return !foo->is_good();
});
vec.erase(new_end, vec.end());
// now `vec` only contains "good" foos.

如果您只想获取原始指针而不是unique_ptr本身,可以使用std::transform填充vector<Foo*>,然后使用remove_if来过滤它......但是在这一点上,编写for循环可能更容易。

std::vector<int*> good_vec;
for (const auto& foo : vec) {
    if (foo->is_good()) {
        good_vec.push_back(foo.get());
    }
}

答案 1 :(得分:2)

由于您的向量包含unique_ptr(我们不会复制) - 我建议您查询第二个选项:迭代器只迭代这些元素匹配你的谓词。这正是boost::filter_iterator

一个例子:

bool points_to_positive(int* ptr) { 
    return ptr != nullptr and *ptr > 0; 
}

// ...

std::vector<std::unique_ptr<int>> vec;

// ...

auto iterator = boost::make_filter_iterator(
    &points_to_positive, std::begin(vec), std::end(vec)
);

但是,如果你计划多次进行迭代,并且不想换空间,那么只需复制出@ kennytm最后建议选项中的实际指针就可能更好了。

答案 2 :(得分:1)

您要求的是来自std::copy_if的{​​{1}}。对于无法复制的<algorithm>元素,这不是您想要的。示例代码:

unique_ptr

但是,您的数组包含#include <algorithm> #include <array> #include <cstdlib> #include <experimental/array> #include <iostream> #include <type_traits> #include <vector> using std::cout; using std::endl; using std::size_t; bool is_even( const int n ) { // True iff n is even. return n % 2 == 0; } std::ostream& operator<< ( std::ostream& os, const std::vector<int>& container ) { // Boilerplate instrumentation. for ( const int& x : container ) os << x << ' '; return os; } int main(void) { // Our input array, raw: constexpr int digits[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // The number of input elements: constexpr size_t ndigits = std::extent<decltype(digits)>(); // Container wrapping our input array: constexpr std::array<int, ndigits > numbers = std::experimental::to_array(digits); std::vector<int> even_numbers; even_numbers.reserve(ndigits); // Upper bound on output size. std::copy_if( numbers.cbegin(), numbers.cend(), std::back_inserter(even_numbers), is_even ); even_numbers.shrink_to_fit(); // Correct output is "2 4 6 8 " cout << even_numbers << endl; return EXIT_SUCCESS; } 个对象,无法复制。几个答案有其他好的建议,以获得相同的结果。但是,如果要将符合要求的引用复制到其他集合,您也可以将unique_ptr更改为unique_ptrshared_ptr,这可以复制。