C++11 中 unique_ptr 的向量
vector of unique_ptr in C++11
我最近切换到 C++11,我正在努力适应那里的良好做法。
我最终经常处理的是:
class Owner
{
private:
vector<unique_ptr<HeavyResource>> _vectorOfHeavyResources;
public:
virtual const vector<const HeavyResource*>* GetVectorOfResources() const;
};
这需要我做一些事情,比如添加一个 _returnableVector 并翻译源向量以便稍后能够 return 它:
_returnableVector = vector<HeavyResource*>;
for (int i=0; i< _vectorOfHeavyResources.size(); i++)
{
_returnableVector.push_back(_vectorOfHeavyResources[i].get());
}
有没有人注意到类似的问题?你的想法和解决方案是什么?我在这里得到了整个所有权的想法吗?
更新:
这是另一件事:
如果一个 class returns 作为 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*>
我建议您不要维护和返回一个未经 unique_ptr
编辑的向量,而是提供直接访问元素的函数。这封装了您的资源存储;客户不知道它们存储为 unique_ptr
s,也不知道它们保存在 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); }
您可能需要考虑 shared_ptr
,因为它可能反映了您正在努力实现的目标。您可能希望在较小的范围内使用 unique_ptr
,或者任何时候您希望使用对象仅反映一件事。
我试过这个:
public:
const std::vector<int const *> getResource()
{
return reinterpret_cast<std::vector<const int *> &>(resources);
}
private:
std::vector<unique_ptr<int>> resources;
成功了。
如果你经常遇到这种情况,写一个 class 可能是有意义的,它的行为类似于 unique_ptr,但将指针的常量传递给它指向的对象。这样,您就可以 return 对向量的 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 上看到了这个地方的更精致的版本,但我现在找不到它。
这是一个示例,说明如何在 class:
中使用它
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 是有效的,反之亦然。
您可以编写适配器,为您提供对元素的不同视图(通过在必要时转换每个元素)但是 - 除了创建适当类型的新向量 - 不存在一般机制(我知道)做什么你要。
我最近切换到 C++11,我正在努力适应那里的良好做法。 我最终经常处理的是:
class Owner
{
private:
vector<unique_ptr<HeavyResource>> _vectorOfHeavyResources;
public:
virtual const vector<const HeavyResource*>* GetVectorOfResources() const;
};
这需要我做一些事情,比如添加一个 _returnableVector 并翻译源向量以便稍后能够 return 它:
_returnableVector = vector<HeavyResource*>;
for (int i=0; i< _vectorOfHeavyResources.size(); i++)
{
_returnableVector.push_back(_vectorOfHeavyResources[i].get());
}
有没有人注意到类似的问题?你的想法和解决方案是什么?我在这里得到了整个所有权的想法吗?
更新:
这是另一件事:
如果一个 class returns 作为 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*>
我建议您不要维护和返回一个未经 unique_ptr
编辑的向量,而是提供直接访问元素的函数。这封装了您的资源存储;客户不知道它们存储为 unique_ptr
s,也不知道它们保存在 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); }
您可能需要考虑 shared_ptr
,因为它可能反映了您正在努力实现的目标。您可能希望在较小的范围内使用 unique_ptr
,或者任何时候您希望使用对象仅反映一件事。
我试过这个:
public:
const std::vector<int const *> getResource()
{
return reinterpret_cast<std::vector<const int *> &>(resources);
}
private:
std::vector<unique_ptr<int>> resources;
成功了。
如果你经常遇到这种情况,写一个 class 可能是有意义的,它的行为类似于 unique_ptr,但将指针的常量传递给它指向的对象。这样,您就可以 return 对向量的 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 上看到了这个地方的更精致的版本,但我现在找不到它。
这是一个示例,说明如何在 class:
中使用它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 是有效的,反之亦然。
您可以编写适配器,为您提供对元素的不同视图(通过在必要时转换每个元素)但是 - 除了创建适当类型的新向量 - 不存在一般机制(我知道)做什么你要。