我有std::unique_ptr<Foo>
个对象的向量。我想获得符合某些条件的所有矢量项的集合。
我看到std函数,但它们似乎都测试谓词(并返回bool)或返回单个元素。
是否有内置机制来获取作为向量子集的集合?如果没有,有没有办法构造一个迭代器,根据任意谓词测试项目(以识别满足我条件的项目)和返回符合该谓词的所有项目的机制?
答案 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_ptr
或shared_ptr
,这可以复制。