什么时候将unique_ptr与STL容器一起使用是有意义的? (C ++ 11)

时间:2012-01-06 21:11:53

标签: c++ coding-style stl c++11 unique-ptr

unique_ptr的容器似乎毫无意义:你不能将它与初始化列表一起使用,而我无法遍历容器(下面的解决方法)。我误会了什么吗?或者何时使用unique_ptr和STL容器?

#include <memory>
#include <vector>

using namespace std;

struct Base { void go() { }  virtual ~Base() { } }; 
// virtual ~Base() = default; gives
// "declared virtual cannot be defaulted in the class body" why?

class Derived : public Base { };

int main() {

  //vector<unique_ptr<Base>> v1 = { new Derived, new Derived, new Derived };
  //vector<shared_ptr<Base>> v2 = { new Derived, new Derived, new Derived };
  vector<Base*> v3 = { new Derived, new Derived, new Derived };
  vector<shared_ptr<Base>> v4(v3.begin(), v3.end());
  vector<unique_ptr<Base>> v5(v3.begin(), v3.end());

  for (auto i : v5) { // works with v4
    i->go();
  }
  return 0;
}

<小时/> 以下问题帮助我找到了这些解决方法:

3 个答案:

答案 0 :(得分:15)

for (auto i : v5) {
  i->go();
}

应该是

for (auto& i : v5) { // note 'auto&'
  i->go();
}

否则你会尝试复制当前元素。

此外,您不能使用这样的初始值设定项列表,因为std::unique_ptrstd::shared_ptr的构造函数标记为explicit。你需要做这样的事情:

#include <iterator> // make_move_iterator, begin, end

template<class T>
std::unique_ptr<T> make_unique(){ // naive implementation
  return std::unique_ptr<T>(new T());
}

std::unique_ptr<Base> v1_init_arr[] = {
    make_unique<Derived>(), make_unique<Derived>(), make_unique<Derived>()
};

// these two are only for clarity
auto first = std::make_move_iterator(std::begin(v1_init_arr));
auto last = std::make_move_iterator(std::end(v1_init_arr));
std::vector<std::unique_ptr<Base>> v1(first, last);

std::vector<std::shared_ptr<Base>> v2 = {
    std::make_shared<Derived>(),
    std::make_shared<Derived>(),
    std::make_shared<Derived>()
};

这是一个Good Thing™,因为否则你可能会泄漏内存(如果后面的一个构造函数抛出,前者还没有绑定到智能指针)。 unique_ptr的tip-toeing是必要的,因为初始化列表会复制他们的参数,并且由于unique_ptr不可复制,所以你会遇到问题。


也就是说,我在我的一个项目中使用std::map<std::string, std::unique_ptr<LoaderBase>>作为加载器字典。

答案 1 :(得分:1)

当容器包含无法复制的对象时,

unique_ptr在STL容器中有意义。或者,如果复制它们很昂贵或者根本不正确。

您将获得与

相同的功能
vector<Base*> v3 = { new Derived, new Derived, new Derived };

但没有v3邀请的内存泄漏。

答案 2 :(得分:1)

你实际上可以使用std::unique_ptr<T>迭代容器而没有问题...你只需要访问唯一指针的引用(即不是副本),或者你需要实际使用迭代器 - 用容器输入。在您的情况下,类似于vector<unique_ptr<Base>>::iteratorvector<unique_ptr<Base>>::const_iterator