web-dev-qa-db-ja.com

GCC 4.7では、初期化リストからunique_ptrsのコンテナを初期化できません

_std::vector<std::unique_ptr<std::string>>_を Bjarne Stroustrupの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>&)'の呼び出しに一致する関数がありません

このエラーを修正する方法は何ですか?

50
juanchopanza

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"} }
};

ただし、コンストラクターの1つが失敗するとリークする可能性があります。 make_unique を使用する方が安全です:

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

しかし... initializer_listsは常にコピーを実行し、unique_ptrsはコピーできません。これは、初期化子リストについて本当に迷惑なものです。 ハックする 、またはemplace_backを呼び出して初期化にフォールバックできます。

スマートポインターを使用して実際にstringsを管理しており、それが例だけではない場合は、さらに改善できます。vector<string>を作成するだけです。 std::stringは、使用するリソースを既に処理しています。

60

あなたの例を「修正」した後:

#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の明示的なコンストラクターを使用できないことを示しています。

3
BЈовић