C ++ 11中unique_ptr的向量

时间:2015-04-29 08:40:23

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

我最近切换到C ++ 11,并且我试图习惯那里的良好实践。 我最终经常处理的是:

class Owner
{
private:
    vector<unique_ptr<HeavyResource>> _vectorOfHeavyResources;
public:
    virtual const vector<const HeavyResource*>* GetVectorOfResources() const;
};

这要求我做一些事情,比如添加一个_returnableVector并翻译源向量以便以后能够返回它:

_returnableVector = vector<HeavyResource*>;
for (int i=0; i< _vectorOfHeavyResources.size(); i++)
{
    _returnableVector.push_back(_vectorOfHeavyResources[i].get());
}

有没有人注意到类似的问题?您有什么想法和解决方案?我在这里获得了所有的所有权意见吗?

更新: 还有另外一件事: 如果一个类将某些处理的结果返回为vector<unique_ptr<HeavyResource>>(它将结果的所有权传递给调用者),并且它应该用于某些后续处理,那该怎么办:

vector<unique_ptr<HeavyResource>> partialResult = _processor1.Process();
// translation
auto result = _processor2.Process(translatedPartialResult); // the argument of process is vector<const HeavyResource*>

3 个答案:

答案 0 :(得分:16)

我建议您不要维护和返回非unique_ptr ed向量,而是提供直接访问元素的函数。这封装了资源的存储空间;客户不知道它们存储为unique_ptr,也不知道它们存放在vector

一种可能性是使用boost::indirect_iterator自动取消引用您的unique_ptr

using ResourceIterator =
     boost::indirect_iterator<std::vector<std::unique_ptr<HeavyResource>>::iterator,
                              const HeavyResource>;
ResourceIterator begin() { return std::begin(_vectorOfHeavyResources); }
ResourceIterator end() { return std::end(_vectorOfHeavyResources); }

Demo

答案 1 :(得分:1)

如果经常遇到这种情况,编写一个类似unique_ptr的类可能是有意义的,但是将指针的常量传递给它指向的对象。这样,您可以只返回向量的const引用。

我最后写了一次并完成了它:

#include <iostream>
#include <vector>
#include <memory>

//unique,const-preserving pointer
template<class T>
class ucp_ptr {
    std::unique_ptr<T> ptr;
public:
    ucp_ptr() = default;
    ucp_ptr(T* ptr) :ptr{ ptr }{};
    ucp_ptr(std::unique_ptr<T>&& other) :ptr(std::move(other)){};

    T&        operator*()       { return ptr.get(); }
    T const & operator*()const  { return ptr.get(); }

    T*        operator->()      { return ptr.get(); }
    T const * operator->()const { return ptr.get(); }
};

struct Foo {
    int a = 0;
};

int main() {
    std::vector<ucp_ptr<Foo>> v;
    v.emplace_back(new Foo());
    v.emplace_back(std::make_unique<Foo>());    

    v[0]->a = 1;
    v[1]->a = 2;

    const std::vector<ucp_ptr<Foo>>& cv = v;

    std::cout << cv[0]->a << std::endl; //<-read access OK
    //cv[1]->a = 10; //<-compiler error
}

当然,如果您需要自定义删除程序或想要添加管理数组的专门化,您可以稍微扩展它,但这是基本版本。我也相信我已经在SO上看过这个som的更精致的版本,但我现在找不到它。

以下是一个如何在类中使用它的示例:

class Bar {
    std::vector<ucp_ptr<Foo>> v;
public:
    void add(const Foo& foo){ 
        v.push_back(std::make_unique<Foo>(foo)); 
    }
    //modifying elements
    void doubleElements() {
        for (auto& e : v){
            e->a *= 2;
        }
    }
    const std::vector<ucp_ptr<Foo>>& showElements() const{
        return v;
    }
};

修改

就您的更新而言,您必须承认vector<T>vector<B>无关的事实,即使将T转换为B也是有效的,反之亦然。
你可以编写适配器,给你一个不同的元素视图(通过在必要时强制转换每个元素)但是 - 除了创建一个正确类型的新向量 - 没有一般的meachanism(我知道)做什么你要。

答案 2 :(得分:-2)

我试过了:

public:
   const std::vector<int const *> getResource()
   {
       return reinterpret_cast<std::vector<const int *> &>(resources);
   }

private:
   std::vector<unique_ptr<int>> resources;

有效。