Garbage Collection

塵も積もれば山

目次

Blog 利用状況

ニュース

C++とかC#とか数学ネタを投下していく予定です。

[その他のページ]
日々の四方山話を綴った日記出水の日記帳

書庫

日記カテゴリ

2008年11月28日 #

[C++/CLI]Stringの糸口

意外に、C++/CLIで検索する方がいるようなので、
C++/CLIを始めたときに混乱していたネタを投下します。

C++/CLIを始めてから、よくわからない印象を持ったのが文字列の扱いです。
ハンドル型なのに実体のような動きをする存在で、不思議に見えました

System::String ^str1 = gcnew System::String("abc");
System::String ^tmpstr = str1;

Console::WriteLine(str1);
Console::WriteLine(tmpstr);

str1 = gcnew System::String(str1 + "def");

Console::WriteLine(str1);
Console::WriteLine(tmpstr);

初期化はchar*と同じようにできますが、なぜか足し算もできます。
演算子オーバーロードでうまくやっているんでしょうと理解していました。

そして、いちばん混乱したのがこれ。

System::String ^str1 ="abc";
System::String ^tmpstr = str1;

Console::WriteLine(str1);
Console::WriteLine(tmpstr);

str1 += "def";

Console::WriteLine(str1);
Console::WriteLine(tmpstr);

もし、char *のように振舞うのであれば、
2回目のWriteLineでは両方とも"abcdef"が出力されないといけませんが、
実際には、str1は"abcdef"、tmpstrは"abc"と出力されます。

しかし、ハンドル型なので実体を持ち運んでいるわけではないはず。
Stringだけ特殊な扱いを受けている??

どうにも解せないときに出会ったキーワードが以下の2つ。
・ボックス化
・String不変

キーワードにしたがって、上のソースを書きなおしてみます。

System::String ^str1 = gcnew System::String("abc");
System::String ^tmpstr = str1;

Console::WriteLine(str1);
Console::WriteLine(tmpstr);

str1 = gcnew System::String(str1 + "def");

Console::WriteLine(str1);
Console::WriteLine(tmpstr);

まず最初の変数初期化ですが、ボックス化によりgcnewが付与されます。
ですから、char*のように先頭ポインタだけを指しているわけではありません。

そして、+=演算子。
これがもう一つのString不変です。
Stringの内容が変化を受ける場合、そのつど新しい領域が確保されます。
ですから、後半のstr1とtmpstrでは指しているアドレスが違うわけでです。

String不変の観点でSystem::Stringを調べてみると、
ハンドル型の変数を書き換えられない状況では、ReadOnlyになっています。
(たとえば、[]演算子)

StringはUnicodeを格納するクラスなので、char*やstd::stringとは違い、
固定文字列を持ち運ぶもの、と理解しておくといいでしょう。

posted @ 6:11 | Feedback (315)