C++ 在STL容器中使用unique_ptr什么时候有意义?(C+;+;11)

C++ 在STL容器中使用unique_ptr什么时候有意义?(C+;+;11),c++,coding-style,stl,c++11,unique-ptr,C++,Coding Style,Stl,C++11,Unique Ptr,unique\u ptr的容器似乎没有什么意义:您不能将其与初始值设定项列表一起使用,并且我无法遍历容器(下面的解决方法)。我是不是误解了什么?或者什么时候使用unique_ptr和STL容器有意义 #include <memory> #include <vector> using namespace std; struct Base { void go() { } virtual ~Base() { } }; // virtual ~Base() = defau

unique\u 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;
}
#包括
#包括
使用名称空间std;
结构Base{void go(){}virtual~Base(){};
//virtual~Base()=默认值;给予
//“不能在类主体中默认声明虚拟”为什么?
派生类:公共基{};
int main(){
//向量v1={新派生,新派生,新派生};
//向量v2={新派生,新派生,新派生};
向量v3={新派生,新派生,新派生};
向量v4(v3.begin(),v3.end());
向量v5(v3.begin(),v3.end());
对于(自动i:v5){//与v4一起使用
i->go();
}
返回0;
}

以下问题帮助我找到了这些解决方法:

应该是

for (auto& i : v5) { // note 'auto&'
  i->go();
}
否则,您将尝试复制当前元素

另外,您不能使用这样的初始值设定项列表,因为
std::unique_ptr
std::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>()
};
#包括//make\u move\u迭代器、begin、end
模板
std::unique_ptr make_unique(){//naive实现
返回std::unique_ptr(new T());
}
std::unique_ptr v1_init_arr[]={
使_唯一(),使_唯一(),使_唯一()
};
//这两个只是为了澄清
auto first=std::make_move_迭代器(std::begin(v1_init_arr));
auto last=std::make_move_迭代器(std::end(v1_init_arr));
std::向量v1(第一个,最后一个);
标准::向量v2={
std::使_共享(),
std::使_共享(),
std::make_shared()
};
这是件好事™, 因为否则您可能会泄漏内存(如果后面的构造函数抛出,那么前面的构造函数还没有绑定到智能指针)。
unique\u ptr
的提示是必要的,因为初始值设定项列表复制了它们的参数,并且由于
unique\u ptr
不可复制,您会遇到问题



也就是说,在我的一个项目中,我使用了一个
std::map
作为加载程序的字典。

unique\u ptr
在STL容器中,当容器包含无法复制的对象时是有意义的。或者如果复制它们的成本很高或者根本不正确

您可以获得与您的应用程序相同的功能

vector<Base*> v3 = { new Derived, new Derived, new Derived };
vector v3={new-Derived,new-Derived,new-Derived};

但是如果没有内存泄漏,
v3
非常诱人。

您实际上可以使用
std::unique\u ptr
在容器中进行迭代,而不会出现问题。。。您只需要访问唯一指针的引用(即,不是副本),或者实际需要在容器中使用迭代器类型。在您的情况下,这可能类似于
vector::iterator
vector::const_iterator

或当您需要多态行为时;尽管有些容器要求它们是可移动的。
vector v1={make_unique(),make_unique(),make_unique()}
正如@Benjamin所提到的,初始值设定项列表根据定义进行复制,因此它们不能用于仅移动的对象。不过,您可以使用数组进行复制:
unique_ptr v1[]={make_unique(),make_unique(),make_unique()
@Xeo示例代码中v1的语法非常糟糕:(我一直在等待C++Ox,但我还是坚持使用C++98,并使用旧语法进行构造,它同样可怕……我错过了重大突破。@Xeo是的,我得到了安全部分。我希望扩展初始值设定项列表后语法会变得更简单,因此我感到失望。
vector<Base*> v3 = { new Derived, new Derived, new Derived };