web-dev-qa-db-fra.com

L'initialisation du conteneur de unique_ptrs à partir de la liste d'initialisation échoue avec GCC 4.7

J'essaie d'initialiser un std::vector<std::unique_ptr<std::string>> D'une manière équivalente à un exemple de FAQ C++ 11 de Bjarne Stroustrup :

using namespace std;
vector<unique_ptr<string>> vs { new string{"Doug"}, new string{"Adams"} }; // fails
unique_ptr<string> ps { new string{"42"} }; // OK

Je ne vois aucune raison pour laquelle cette syntaxe devrait échouer. Y a-t-il un problème avec cette façon d'initialiser le conteneur?
Le message d'erreur du compilateur est énorme; le segment pertinent que je trouve est ci-dessous:

/usr/lib/gcc-snapshot/lib/gcc/i686-linux-gnu/4.7.0/../../../../include/c++/4.7.0 /bits/stl_construct.h:77 : 7: erreur: pas de fonction correspondante pour l'appel à 'std::unique_ptr<std::basic_string<char> >::unique_ptr(std::basic_string<char>&)'

Quelle est la façon de corriger cette erreur?

54
juanchopanza

Le constructeur de unique_ptr Est explicit. Vous ne pouvez donc pas en créer un implicitement avec à partir de new string{"foo"}. Il doit s'agir de quelque chose comme unique_ptr<string>{ new string{"foo"} }.

Ce qui nous amène à cela

// not good
vector<unique_ptr<string>> vs {
    unique_ptr<string>{ new string{"Doug"} },
    unique_ptr<string>{ new string{"Adams"} }
};

Cependant, il peut fuir si l'un des constructeurs tombe en panne. Il est plus sûr d'utiliser make_unique :

// does not work
vector<unique_ptr<string>> vs {
     make_unique<string>("Doug"),
     make_unique<string>("Adams")
};

Mais ... initializer_list S effectuent toujours des copies et unique_ptr Ne sont pas copiables. C'est quelque chose de vraiment ennuyeux avec les listes d'initialisation. Vous pouvez pirater , ou revenir à l'initialisation avec des appels à emplace_back.

Si vous gérez réellement strings avec des pointeurs intelligents et que ce n'est pas seulement pour l'exemple, alors vous pouvez faire encore mieux: faites simplement un vector<string>. Le std::string Gère déjà les ressources qu'il utilise.

60

Après avoir "corrigé" votre exemple:

#include <vector>
#include <memory>
#include <string>

int main()
{
    std::vector<std::unique_ptr<std::string>> vs = { { new std::string{"Doug"} }, { new std::string{"Adams"} } }; // fails
    std::unique_ptr<std::string> ps { new std::string{"42"} }; // OK
}

J'ai un message d'erreur très clair:

error: converting to 'std::unique_ptr<std::basic_string<char> >' from initializer list would use explicit constructor 'std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = std::basic_string<char>, _Dp = std::default_delete<std::basic_string<char> >, std::unique_ptr<_Tp, _Dp>::pointer = std::basic_string<char>*]'

Cette erreur indique qu'il n'est pas possible d'utiliser le constructeur explicite de unique_ptr.

3
BЈовић