質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

1699閲覧

C++における、vector<Class Hoge>のインスタンス生成方法

Tatatatatana

総合スコア11

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/07/15 04:19

前提・実現したいこと

C++で開発を行っている初心者です。
解決方法がわからないので教えてください。

該当ソースは以下のMakeEquipmentListです。
簡略化しておりますが、
Enchantクラスにprivateで保持しているvector<Equipment> _equipmentListを生成しようとしているメソッドです。

しかし、この状態ではループが終了した時点でスコープ外となり、_equipmentListの中身が開放されてしまいます。
理屈はわかるのですが、
ループやメソッドを抜けたとしてもデータを保持するためには、具体的にどのようにコーディングすれば良いのかがわからないので教えてください。
よろしくおねがいします。

該当のソースコード

C++

1void Enchant::MakeEquipmentList() { 2 vector<vector<string>> tmp = { { "sword", "10", "20" }, {"armor", "30", "40"} }; 3 for (auto itr = tmp.begin(); itr != tmp.end(); itr++) { 4 vector<string> tmp = (*itr); 5 Equipment *equip = new Equipment(&tmp); 6 _equipmentList.push_back(*equip); 7 } 8} 9 10class Enchant { 11public: 12 MakeEquipmentList(); 13private: 14 std::vector<Equipment> _equipmentList; 15}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

こんにちは。

この状態ではループが終了した時点でスコープ外となり、_equipmentListの中身が開放されてしまいます。

Equipmentクラスの実装次第ですよ。Equipment(std::vector<std::string>* tmp)コンストラクタがtmpをコピーして保持すれば大丈夫なはずです。tmpのポインタや参照で保持するとダメです。

C++

1#include <iostream> 2#include <string> 3#include <vector> 4 5using namespace std; 6 7class Equipment 8{ 9 std::vector<std::string> data; 10public: 11 Equipment(std::vector<std::string>* tmp) : data(*tmp) { } 12 void print() const 13 { 14 for (auto const& item : data) 15 { 16 std::cout << item << " "; 17 } 18 std::cout << "\n"; 19 } 20}; 21 22class Enchant { 23public: 24 void MakeEquipmentList(); 25 void print() const 26 { 27 for (Equipment const& equipment : _equipmentList) 28 { 29 equipment.print(); 30 } 31 } 32private: 33 std::vector<Equipment> _equipmentList; 34}; 35 36void Enchant::MakeEquipmentList() { 37 vector<vector<string>> tmp = { { "sword", "10", "20" }, {"armor", "30", "40"} }; 38 for (auto itr = tmp.begin(); itr != tmp.end(); itr++) { 39 vector<string> tmp = (*itr); 40 Equipment *equip = new Equipment(&tmp); 41 _equipmentList.push_back(*equip); 42 } 43} 44 45int main() 46{ 47 Enchant enchant; 48 enchant.MakeEquipmentList(); 49 enchant.print(); 50}

更に、C++11以降であれば、std::initializer_listを受け取るstd::vectorのコンストラクタ(左のリンク先の「例」参照)を使うとMakeEquipmentList()をよりスッキリ記述できます。


【ミスが会ったので修正】

std::initializer_listを受け取るstd::vectorのコンストラクタ(左のリンク先の「例」参照)を使うと

の記載はミスでした。以下へ訂正します。

Equepmentにstd::initializer_listを受け取るコンストラクタを定義してstd::vecotrへ渡す(cppreffpの例参照)と

投稿2019/07/15 05:16

編集2019/07/15 05:41
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tatatatatana

2019/07/15 05:27

回答有り難うございます。 解決しました! 例で示してくださったEquipmentクラスのdataが、僕の作成したものではポインタとなっていたことが原因でした。 コンストラクタにて値コピーをするよう変更しました。
Tatatatatana

2019/07/15 05:33

std::initializer_listについても初耳でしたので助かります。勉強になりました。
Chironian

2019/07/15 05:36

うまく行ってよかったです。 ところで、私の回答に一部ミスがありました。修正しますね。
Tatatatatana

2019/07/15 06:04

意味は伝わっておりました。ありがとうございます。
guest

0

あまり詳しくないですが、
保持する方をポインタにしてはいかがですか?
最近の方法であればshared_pointerとかのスマートポインタっていうやつ。

つまり、私が言いたいのは、仮に生のポインタだとしたら、

C++

1class Enchant { 2public: 3 MakeEquipmentList(); 4private: 5 std::vector<Equipment> _equipmentList; // <- これ! 6}

を、ポインタを保持するようにして、

C++

1class Enchant { 2public: 3 MakeEquipmentList(); 4private: 5 std::vector<Equipment*> _equipmentList; // <- これ! 6}

とする。この場合は デストラクタで vector内にあるオブジェクトをdeleteしないといけませんが、
これなら保持できる。

私の考えでは(※ 正しいわけではないことに注意) MakeEquipmentListメンバ関数内ではEquipmentをnewで生成している。

そして、その実体をメンバ変数として保持していますね。

だから関数から離れた瞬間に破棄されるのでは?

(趣味でやっているのでうのみにはしないでください...)

投稿2019/07/15 05:03

BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tatatatatana

2019/07/15 05:16

回答ありがとうございます。 定義をご指摘のとおりvector<Equipment*> _equipmentListに修正し、ループの中を以下のようにしましたが、結果は変わらずでした。 何か他に改善点など思いつきますでしょうか。 vector<string> tmp = (*itr); _equipmentList.push_back(new Equipment(&tmp));
Tatatatatana

2019/07/15 05:28

解決しました。ありがとうございました。
guest

0

これで問題ないのではないでしょうか。

C++

1_equipmentList.push_back(Equipment(&tmp));

下手にポインタを介するから煩雑になるわけで、push_backconst T&からのコピー、あるいはT&&からのムーブで格納されるので(cpprefjp)、そのまま一時オブジェクトを渡して問題ありません。

投稿2019/07/15 04:50

編集2019/07/15 04:55
maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/07/15 04:58

元のコードの場合も、vectorにはnewしたオブジェクトのコピーが入るため、動くことは動きます(逆に。newしたオブジェクトをdeleteしていないので、そちらがメモリリークするほうが問題になります)。
Tatatatatana

2019/07/15 05:15

回答有り難うございます。 一時変数を撤去し以下のように修正しましたが、結果は変わらずでした。 何か他に改善点など思いつきますでしょうか。 vector<string> tmp = (*itr); _equipmentList.push_back(*new Equipment(&tmp));
Tatatatatana

2019/07/15 05:28

解決しました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問