【问题标题】:C++11 container of borrowed unique_ptrs借用的 unique_ptrs 的 C++11 容器
【发布时间】:2016-01-07 08:18:55
【问题描述】:

我有一个 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 可能没有意义。但是,它纯粹是只读的!所以应该有一些方法来完成这项工作。 ``things'' 的生命周期保证比被过滤的东西要大。

请注意,调用者拥有提供的参数。

【问题讨论】:

  • 您应该与 std::shared_ptr 共享所有权或分配副本。与unique_ptr 共享所有权是没有意义的。
  • 我认为您需要重新考虑您的设计...您确定要在此处使用std::unique_ptr 吗?如果您想拥有多个所有者,std::shared_ptr 会更有意义。
  • 你可以用ref创建reference_wrappers
  • 我要说明的是,无论是谁使用函数的返回值,都不能控制Things的寿命。
  • 您可以简单地将原始指针存储在过滤后的向量中。

标签: c++11 unique-ptr lifetime ownership


【解决方案1】:

你可以从&lt;functional&gt;使用reference_wrapper

#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;
}

【讨论】:

    【解决方案2】:

    如果您想要的是获得一组过滤的元素而不是包含它们的实际容器,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&lt;std::shared_ptr&lt;Thing&gt; &gt; 并返回std::vector&lt;std::weak_ptr&lt;Thing&gt; &gt;。在从 things 删除它之前,您可以检查它是否真的是 std::shared_ptr::unique() 的唯一且唯一的 ptr。

    【讨论】:

      猜你喜欢
      • 2014-07-19
      • 2016-01-13
      • 2013-01-17
      • 2013-07-02
      • 1970-01-01
      • 2012-10-21
      • 1970-01-01
      • 2020-09-19
      • 2012-03-07
      相关资源
      最近更新 更多