vectorにスタック変数を格納(C++)

研究で使っているC++のプログラムを見返しているうちに、非常に初歩的な疑問が湧き、速攻で解決して感動したのでメモ。

3年前に書いたプログラムでは、
STLコンテナ(vectorとかmapとか)に自作クラスのオブジェクトを格納したいとき、

vector<Hoge*> v;
v.push_back(new Hoge());

のような書き方をしていた。おそらくJavaの影響で。
もちろん、メモリ解放用のコードも書いてあった。

しかし、他人からのもらいもののコードの中で

vector<Hode> v;
v.push_back(Hoge());

というコードを見た覚えがあった。

そのときは、気にしなかったが、
今になってふっと

「スタック変数をpush_back()したはずなのに、スコープ抜けた後でもちゃんと動いてるのはなんでだ」

という疑問が湧いた、と同時に、2つ目のコードのほうがdeleteのためのコードが不要になってうれしいことに気付いた。

なぜ問題のコードは動くのか。

「vectorに格納されているインスタンスと渡したインスタンスが別物なんじゃないか?」

という考えに行きついたところで、仮引数と実引数のことを思い出した。

考えてみればpush_back()って関数だよな、と。

初歩的すぎて、なんでも無いことかもしれないが、知識としてだけ頭の中に存在する情報がつながったときは、やはり気持ちがいい。

 

—2014.06.28に追記—

vectorはヒープ領域に変数を格納するので、new/deleteはvectorが勝手にやってくれる。
したがって、格納されているインスタンスのdeleteをプログラマは書かなくても良い。

サンプルコードを新しくした。

【確認用サンプルコード】

#include <vector>
#include <iostream>
class Hoge
{
protected:
int m;
Hoge* p;
public:
Hoge(int x)
:m(x),
p(this)
{
std::cout << "–Hoge(int)–" << std::endl;
std::cout << "コンストラクタの呼び出し" << std::endl;
std::cout << "本オブジェクトのアドレス" << this << std::endl;
std::cout << "" << std::endl;
}
Hoge(const Hoge& hoge)
:m(hoge.m),
p(this)
{
std::cout << "–Hoge(const Hoge&)–" << std::endl;
std::cout << "コピーコンストラクタの呼び出し" << std::endl;
std::cout << "コピーされるオブジェクトのアドレス" << hoge.p << std::endl;
std::cout << "新たに作成された本オブジェクトのアドレス" << this << std::endl;
std::cout << "" << std::endl;
}
~Hoge()
{
std::cout << "–~Hoge()–" << std::endl;
std::cout << "デストラクタの呼び出し" << std::endl;
std::cout << "本オブジェクトのアドレス" << this << std::endl;
std::cout << "" << std::endl;
}
int getM(void) const { return m; }
};
int main()
{
std::vector<Hoge> v;
{
std::cout << "Hoge h(3)でHogeインスタンスを作成" << std::endl;
Hoge h(3);
std::cout << "作成したインスタンスのアドレス" << &h << std::endl;
std::cout << "v.push_back(h)でHogeオブジェクトをvectorに格納" << std::endl;
v.push_back(h);
std::cout << "格納されたインスタンスのアドレス" << &v[0] << std::endl;
std::cout << "ココでスコープを抜ける" << std::endl;
}
std::cout << "格納されたインスタンスのアドレス" << &v[0] << std::endl;
std::cout << "v[0]のmの値 : " << v[0].getM() << std::endl;
// 実行結果(例)
// Hoge h(3)でHogeインスタンスを作成
// コンストラクタの呼び出し
// 本オブジェクトのアドレス0045F8E0
// 作成したインスタンスのアドレス0045F8E0
// v.push_back(h)でHogeオブジェクトをvectorに格納
// コピーコンストラクタの呼び出し
// 本オブジェクトのアドレス009B4FE8
// 格納されたインスタンスのアドレス009B4FE8
// v[0]のmの値 : 3
return 0;
}

紹介 mkacky
情報工学系の大学院生(D2/2013年現在)

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。