プロが教えるわが家の防犯対策術!

 お世話になります。

 以下のようなソースを書いた場合の、内側のブロックでgcnewしたオブジェクトのスコープ(生存期間)について質問させてください。


value struct STRA
{
 String ^str;
};

int _tmain(int argc, _TCHAR* argv[])
{
 ArrayList ^ar = gcnew ArrayList();
 IEnumerator ^en;

 {
  ArrayList ^ar2 = gcnew ArrayList();
  STRA ^strA = gcnew STRA;
  strA->str = gcnew String("TEST");

  ar2->Add(strA);
  ar = ar2;
}

 en = ar->GetEnumerator();
 en->MoveNext();
 STRA ^strB = safe_cast<STRA>(en->Current);

 return 0;
}

 内側のブロックにて、「ar = ar2」の時点でar2にAddされたオブジェクトのアドレスが入っているようのですが、その後ブロックを抜けた後でもarを通じて内側のブロックで生成したのオブジェクト(strA)の値を見ることができます。
 これは、たまたまガベージコレクトがまだ働いていないためであって、やはり基本的にはブロック内で生成されたオブジェクトをブロックの外で見るべきではない、と考えたほうがよいのでしょうか。

 やはり「ar = ar2」のようにするのではなく、ar2にAddされたオブジェクトをar1に再びAddしていったほうが無難でしょうか。


 何卒ご教示をお願いいたします。

A 回答 (1件)

C++/CLI については、文法について軽くチェックした程度ですが、オブジェクト指向的にはC#と同じだと思いますので、回答します。



スコープを外れるとar2にアクセスできなくなるのはその通りです。が、それはar2という変数の話であって、ar2の指していたオブジェクトとは関係がありません。
この場合は、「もともとar2が指していたものは、arを通して参照しても良い」んです。

勘違いがあると思われるポイントは、gcnewなりnewなりするところ。たとえば
 ArrayList ^ar = gcnew ArrayList();
とあったら、これは、
・arという、ArrayListへの参照(ごめんなさい、CLI用語知らないのでここは不正確です)を宣言する
・gcnew ArrayList()により、新しいArrayListオブジェクトを作成する
・作成したオブジェクト へ の 参 照 を、arにおさめる
と言うことをしています。
作成した新しいオブジェクトはオブジェクト、変数arに入っているのはそのオブジェクトへ至る道でしかないわけです。
道がなくなったオブジェクトがGCの対象になります。
オブジェクトは色んな変数から参照されても構いませんし、元々参照していた変数とはたいした関係がありません。

変数とオブジェクトとの区別さえつければ、あとは簡単に分かるはずです。

ar = ar2 とコピーをした場合でも、ここで行われているのは
・ar2におさめられた「オブジェクトへの参照」をarに入れる
ことだけです。局所変数として宣言されているar2が失われたあとも、ar2が指していた先のオブジェクトは、今度はarが指し示していることになります。従ってそのオブジェクトのGCは行われません。

逆に、前にarに入っていたオブジェクトは、arから指し示されなくなりましたので、GCの対象になります。

簡単にまとめると、
 ・スコープは変数名についての話
 ・変数とオブジェクトは別物
 ・変数はオブジェクトを指し示しているだけ
 ・指し示している変数がなくなるとオブジェクトはGCの対象にされる
ということです。

とても良い疑問だと思います。がんばってください。
    • good
    • 0
この回答へのお礼

 ご回答、ありがとうございます。
 変数とオブジェクトの関係について、非常によく理解できました。
 変数はあくまでもオブジェクトへの参照という意味合いなのですね。
 普段使っているノーマルなCのイメージでいくとダメなはずだよなぁ……と考え込んでしまっていたのですが、これですっきりしました。

 本当にありがとうございました。

お礼日時:2008/03/19 09:27

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!