VC.NET ~ StringクラスとStringBuilderクラス

本文

Stringはimmutableなので、文字列の切り貼りを何度も繰り返す処理を書くときは、中間オブジェクトの生成によるパフォーマンス低下を避けるため、StringBuilderクラスを使いましょう。以上です。

もっと詳しく?

文字列を連結する、文字列から部分文字列を取り出す、文字列を大文字に変換する……。Stringクラスを使えば、こういった処理を簡単に書くことができます。しかし注意すべきは、Stringクラスがimmutableだという点です。immutableというのは、変えられないということです。つまり、Stringオブジェクトの文字列は、コンストラクト時に初期化されたら、それ以降変更できません。Stringを加工するときは、その都度、新しいStringオブジェクトが生成されているわけです。

String^ s = "abc";
s = (s + "xyz")->Substring(1, 4)->ToUpper();
Console::WriteLine(s);                          // BCXY

上記のコードでは4つのStringオブジェクト("abc"、"abcxyz"、"bcxy"、"BCXY")が生成されます。メモリの無駄だけではありません。例えば長さ1000文字の文字列に1文字を連結した場合、1000文字分のmemcpyが行われるわけですから、パフォーマンスにもインパクトがあります。

一般に、コードはパフォーマンスよりも読み易さを優先して書き、パフォーマンス改善は(プロファイリングに基づいて)ボトルネックに対してのみ行った方が効率が良いのでしょうが、Stringに関しては例外的に最初から対策することが多いようです。遅いのが分かりきっているので。

で、その対策とは何か? System::Text::StringBuilderクラスを使うことです。StringBuilderはmutableな文字列と考えて良いでしょう。

StringBuilder^ sb = gcnew StringBuilder("abc");
sb = sb->Append("xyz")->Remove(0, 1)->Remove(4, 1);
for ( int i = 0; i < sb->Length; i++ ) { sb[i] = Char::ToUpper(sb[i]); }
Console::WriteLine(sb->ToString());

この辺の事情はJavaでも同様です。Javaの場合、immutableなStringに対し、mutable文字列としてStringBuilderとStringBufferの2つが用意されています。StringBufferはスレッドセーフに実装されているそうです。.NETのSystem::Text::StringBuilderの場合、staticメソッドのみスレッドセーフのようです。

Last modified:2012/05/10 22:04:41
Keyword(s):
References:[.NETアプリ開発]
This page is frozen.