合計 昨日 今日

[C++]vector<unique_ptr<T>>の初期化

[このトピックは解決済みです]

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: purin52002
[URL]
中級者(14,906 ポイント)
Date: 2017年3月19日(日) 23:18
No: 1
(OFFLINE)

 [C++]vector<unique_ptr<T>>の初期化

こんにちは
スマポを知ってから生ポwwwぬるぽwwwな者です。

今回はboostではなくc++標準のunique_ptrについて質問があります。

コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
class Base;//定義は省略
class A : public Base;//同上
class B : public Base; //同上
 
int main()
{
    vector<unique_ptr<Base> > p_vec  { make_unique<A>(), make_unique<B>() } ;//error
 
    p_vec.push_back(make_unique<A>() );//こっちはセーフ
}


上のようなコードで、vectorの初期化時にunique_ptrをつっこむとエラーが出ます。
おそらく内部でコピーコンストラクタが呼ばれているのかな?と思います。

現在はpush_backを使って一つづつ格納していますが、醜いような気がします。
(あと、新しい要素を追加するときにpush_backって書くのがめんどくさい^^;

ここで質問なのですが、vectorの初期化時にunique_ptrを格納することは可能でしょうか?
また、もし可能であるならそのやり方を教えてもらいたいです。

よろしくお願いします<(_ _)>
c++初心者を自負しています。
質問者さんには今後私にプログラミングを教えてくれるようにやさしく丁寧に教えるつもりです。ぎぶあんどていく^p^
回答者さんには精一杯感謝します。ぎぶおんりー^p^

Name: inemaru
[URL]
上級者(15,871 ポイント)
Date: 2017年3月21日(火) 13:00
No: 2
(OFFLINE)

 Re: [C++]vector<unique_ptr<T>>の初期化

purin52002 さんが書きました:ここで質問なのですが、vectorの初期化時にunique_ptrを格納することは可能でしょうか?
また、もし可能であるならそのやり方を教えてもらいたいです。


自前で、格納する機能を作る必要があると思います。

例えば、
初期化リストを受け取って、vector<unique_ptr<Base>> を返却する関数を作れば可能。
手元で確認していませんが、関数のイメージとしては、
初期化リスト受け取り→reserveで要素数指定→emplace_backで格納
が良いと思います。

Offtopic :
purin52002 さんが書きました:現在はpush_backを使って一つづつ格納していますが、醜いような気がします。
(あと、新しい要素を追加するときにpush_backって書くのがめんどくさい^^;


特に理由がないのであれば、emplace_backの方が効率良いと思います。

Name: purin52002
[URL]
中級者(14,906 ポイント)
Date: 2017年3月22日(水) 00:10
No: 3
(OFFLINE)

 Re: [C++]vector<unique_ptr<T>>の初期化

inemaruさん
素晴らしいアイデアをありがとうございます。
目から鱗でした。
早速使わせていただきたいと思います。

emplace_backについてなのですが、
私の認識ではコピーしないpush_backのイメージでした。
unique_ptrはコピーができない(moveされる)のでpush_backでもいいのかな、と思っていたのですが
やはりemplace_backのほうが効率がいいのでしょうか?
(名前が複雑という理由だけで使わず嫌いを起こしています^^;)
c++初心者を自負しています。
質問者さんには今後私にプログラミングを教えてくれるようにやさしく丁寧に教えるつもりです。ぎぶあんどていく^p^
回答者さんには精一杯感謝します。ぎぶおんりー^p^

Name: zeek
[URL]
Date: 2017年3月22日(水) 00:29
No: 4
(OFFLINE)

 Re: [C++]vector<unique_ptr<T>>の初期化

purin52002 さんが書きました:現在はpush_backを使って一つづつ格納していますが、醜いような気がします。
(あと、新しい要素を追加するときにpush_backって書くのがめんどくさい^^;

ここで質問なのですが、vectorの初期化時にunique_ptrを格納することは可能でしょうか?

初期化ではありませんが、一旦 配列 か array を使用して move した方がスマートかと...
コード[C++]: 全て選択
1
2
3
    array<unique_ptr<Base>, 2> a = { make_unique<A>(), make_unique<B>() };
    vector<unique_ptr<Base> > p_vec;
    std::move(a.begin(), a.end(), back_inserter(p_vec));

Name: inemaru
[URL]
上級者(15,871 ポイント)
Date: 2017年3月22日(水) 03:31
No: 5
(OFFLINE)

 Re: [C++]vector<unique_ptr<T>>の初期化

purin52002 さんが書きました:emplace_backについてなのですが、
私の認識ではコピーしないpush_backのイメージでした。
unique_ptrはコピーができない(moveされる)のでpush_backでもいいのかな、と思っていたのですが
やはりemplace_backのほうが効率がいいのでしょうか?
(名前が複雑という理由だけで使わず嫌いを起こしています^^;)


emplace_backは直にメモリに格納するので、
一時変数のmoveが走らない分、効率が良いと考えています。

関数の実装については、
zeek さん提示の方法で実装した方がスマートに書けますね。
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <memory>
#include <vector>
 
struct Base{};
struct A : public Base{};
struct B : public Base{};
 
// vector<unique_ptr<Base>>を返却する
template <class BaseType, class... Args>
std::vector<std::unique_ptr<BaseType>> make_unique_ptrs(Args&&... args)
{
    using namespace std;
    unique_ptr<BaseType> init[] { forward<Args>(args)... };
    return vector<unique_ptr<BaseType>> { make_move_iterator(begin(init)), make_move_iterator(end(init)) };
}
 
int main()
{
    using namespace std;
    auto ptrs = make_unique_ptrs<Base>(make_unique<A>(), make_unique<B>());
    return 0;
}

Name: purin52002
[URL]
中級者(14,906 ポイント)
Date: 2017年3月22日(水) 12:10
No: 6
(OFFLINE)

 Re: [C++]vector<unique_ptr<T>>の初期化

[解決!]

zeekさん
ありがとうございます。おかげでうまくいきました。
生の配列なんて久しく使っていなかったのですが、配列のことちょっとなめてましたね、、、

inemaruさん
初期化リストを使えと聞いて真っ先に思い浮かんだのがinitializer_listでした。
それからinitializer_listで実装してみたところ「A型とB型の初期化子ってなんやねん」と怒られ、「Base型のリストだよ」と明示していました。
とても醜かったのでまたこちらで質問するかどうかで悩んでいたところにinemaruさんの追記でした^^

可変引数に右辺値参照にforwardに、、、
実際に使うのはどれも初めてでした^^;テンプレート引数を可変にできることなんて初めて知りました^^;
おかげですっきりしたコードにできましたし、自分の技量のなさを改めて実感しましたorz

なにはともあれ、おかげさまで無事解決です^^
ありがとうございました。

Offtopic :
inemaru さんが書きました:emplace_backは直にメモリに格納するので、
一時変数のmoveが走らない分、効率が良いと考えています。

一時変数が作られないということで、今後は徐々にemplace_backに置き換えていこうと思います^^
c++初心者を自負しています。
質問者さんには今後私にプログラミングを教えてくれるようにやさしく丁寧に教えるつもりです。ぎぶあんどていく^p^
回答者さんには精一杯感謝します。ぎぶおんりー^p^


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[13人]