我有一个 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_ptr
或weak_ptr
,可以复制。