Сбой инициализации контейнера unique_ptrs из списка инициализаторов в GCC 4.7 - PullRequest
49 голосов
/ 08 марта 2012

Я пытаюсь инициализировать std::vector<std::unique_ptr<std::string>> таким образом, который эквивалентен примеру из Bjarne Stroustrup's C ++ 11 FAQ :

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

Я не вижу причинпочему этот синтаксис должен потерпеть неудачу.Что-то не так с этим способом инициализации контейнера?
Огромное сообщение об ошибке компилятора;соответствующий сегмент, который я нахожу ниже:

/ usr / lib / gcc-snapshot / lib / gcc / i686-linux-gnu / 4.7.0 /../../../../include/c++/4.7.0 /bits/stl_construct.h:77:7: ошибка: нет соответствующей функции для вызова 'std::unique_ptr<std::basic_string<char> >::unique_ptr(std::basic_string<char>&)'

Как исправить эту ошибку?

Ответы [ 2 ]

59 голосов
/ 08 марта 2012

unique_ptr конструктор explicit. Таким образом, вы не можете создать его неявно с помощью new string{"foo"}. Это должно быть что-то вроде unique_ptr<string>{ new string{"foo"} }.

Что приводит нас к этому

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

Однако может произойти утечка в случае сбоя одного из конструкторов. Безопаснее использовать make_unique:

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

Но ... initializer_list s всегда выполняет копии, а unique_ptr s не копируются. Это действительно раздражает списки инициализаторов. Вы можете взломать его или вернуться к инициализации с вызовами на emplace_back.

Если вы на самом деле управляете string с помощью умных указателей, и это не только для примера, то вы можете сделать еще лучше: просто сделайте vector<string>. std::string уже обрабатывает ресурсы, которые он использует.

3 голосов
/ 08 марта 2012

После «исправления» вашего примера:

#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
}

Я получил очень четкое сообщение об ошибке:

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>*]'

Эта ошибка говорит о том, что невозможно использовать явный конструктор unique_ptr.

...