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



我有一个 std::unique_ptr<Foo>对象的向量。我想获得与某些条件相匹配的所有向量项目的集合。我看到了STD功能,但它们似乎都在测试谓词(并返回BOOL)或返回单个元素。

是否有一种内置机制来获取作为向量子集的集合?如果没有,是否有一种方法可以构建针对任意谓词(确定符合我的状况的谓词)测试项目的迭代器,以及一种返回所有符合谓词的项目的机制?

被警告,由于您有一个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.

如果订单不重要,请改用std::partition。用法相同。

如果要将不良的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());

如果您不再关心"不良"对象,请使用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进行过滤...但是此时循环。

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

由于您的向量持有unique_ptr的s(我们不制作副本) - 我建议您询问的第二个选项:仅迭代这些元素与您的谓词匹配的元素。这正是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的最后建议选择的实际指针来更好地为您服务。

您要求的是<algorithm>中的std::copy_if。对于无法复制的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_ptr更改为shared_ptrweak_ptr,可以复制。

相关内容

  • 没有找到相关文章

最新更新