我有一个unique_ptrs矢量,想要将它过滤成一个相同类型的新矢量。
vector<unique_ptr<Thing>> filter_things(const vector<unique_ptr<Thing>> &things) {
vector<unique_ptr<Thing>> things;
// i want the above line to be something like: vector<const unique_ptr<Thing> &>
// but I don't think this is valid
for (const unique_ptr<Thing> &thing : things) {
if (check(thing)) {
filtered.push_back(thing); // this part shouldn't work since it
// would duplicate a unique_ptr
}
}
return filtered;
}
我希望呼叫者保持所有事物的所有权。我希望这个函数的返回值纯粹只读(const),我不想复制,因为复制Thing非常昂贵。
实现这一目标的最佳方法是什么?
这是否可以使用unique_ptrs?
在某种意义上,我们通过返回一个新的引用向量来创建多个引用,因此unique_ptr可能没有意义。但是,它纯粹是只读的!所以应该有一些方法来使这项工作。 “事物”的生命周期&#39;保证比过滤的东西大。
请注意,调用者拥有所提供的参数。
答案 0 :(得分:1)
您可以使用reference_wrapper
<functional>
#include <memory>
#include <functional>
#include <vector>
#include <iostream>
using namespace std;
struct Thing {};
using PThing = unique_ptr<Thing>;
using RefThing = reference_wrapper<const PThing>;
vector<RefThing> filter_things( const vector<PThing>& things )
{
vector<RefThing> filtered;
int i = 0;
for( auto&& thing : things )
{
if( i++%2 )
filtered.push_back( ref(thing) );
}
return filtered;
}
int main()
{
vector<PThing> vec;
vector<RefThing> flt;
vec.resize(25);
flt = filter_things(vec);
cout << flt.size() << endl;
}
答案 1 :(得分:0)
如果你想要的是获得过滤的元素集而不是包含它们的实际容器,boost::range
可以是一个很好的解决方案。
auto filtered_range(const std::vector<std::unique_ptr<Thing>> &things) {
return things | boost::adaptors::filtered([](const auto& thing) {
return check(thing);
});
}
我使用了一些c ++ 14语法,但我认为很难将它变成c ++ 11。
你可以这样使用它。
std::vector<std::unique_ptr<Thing> > things;
for(const auto& thing : filtered_range(things)) {
// do whatever you want with things satisfying 'check()'
}
缺点之一是范围本身不是容器,因此如果您多次遍历范围,则会检查每个“事物”是否满足check()
。
如果存储已检查事物的容器和控制事物生命周期的容器是您真正想要的,我希望使用std::vector<std::shared_ptr<Thing> >
并返回std::vector<std::weak_ptr<Thing> >
。在从std::shared_ptr::unique()
删除之前,您可以检查它是否真的是things
的唯一ptr。