Contents Up Previous Next 原文へのリンク

wxStringの概要 wxString overview

Classes: wxString, wxArrayString, wxStringTokenizer

イントロダクション
wxStringと他の文字列クラスの比較
wxStringを使う上でのアドバイス
その他の文字列に関した関数とクラス
参照カウントと,それを開発者が気にしないで良い理由
あなたのアプリケーションのためのwxStringのチューニング

Introduction
Comparison of wxString to other string classes
Some advice about using wxString
Other string related functions and classes
Reference counting and why you shouldn't care about it
Tuning wxString for your application


イントロダクションIntroduction

wxStringは任意の長さ(32bitマシン上では通常2147483647であるMAX_INTに制限される)と 任意の文字を含む文字列を表現するクラスである。ASCII NUL文字は許されるが、しかし、それを含む 文字列を他の関数へ渡す際には注意しなければならない。

wxStringはASCII(従来の、7または8bitの文字)でもUnicode(ワイドキャラクタ)でも同様に動作する。

このクラスは、あなたが文字列クラスに期待する全ての標準的操作を持っている:ダイナミック・メモリ・マネージメント( 文字列は新しい文字を収容するために拡張する)、他の文字列からの構築、C文字列と文字、代入演算子、 個々の文字へのアクセス、文字列の連結と比較、サブストリングの抽出、case変換(訳注:大文字、小文字の変換)、 トリミングとパディング(スペースで)、検索と置き換え、そしてCライクな Printf() とストリームライクな挿入機能、などなど。 - 全ての機能リストに関してはwxString を参照のこと。

wxString is a class which represents a character string of arbitrary length (limited by MAX_INT which is usually 2147483647 on 32 bit machines) and containing arbitrary characters. The ASCII NUL character is allowed, although care should be taken when passing strings containing it to other functions.

wxString works with both ASCII (traditional, 7 or 8 bit, characters) as well as Unicode (wide characters) strings.

This class has all the standard operations you can expect to find in a string class: dynamic memory management (string extends to accommodate new characters), construction from other strings, C strings and characters, assignment operators, access to individual characters, string concatenation and comparison, substring extraction, case conversion, trimming and padding (with spaces), searching and replacing and both C-like Printf() and stream-like insertion functions as well as much more - see wxString for a list of all functions.


wxStringと他の文字列クラスの比較Comparison of wxString to other string classes

C文字列を直接操作する代わりに特別な文字列クラスを使う事の利点は非常に明白なので、このように莫大な数の利用可能なクラスがあるのだ。最も重要な利点は、C文字列はメモリ割り当てと解放を忘れずにする必要があるということだ;固定サイズのバッファの操作は殆ど必然的にバッファオーバーフローを引き起こす。最後に、C++は標準の文字列クラスを持っている。それなのになぜwxStringが必要なのだろう?

The advantages of using a special string class instead of working directly with C strings are so obvious that there is a huge number of such classes available. The most important advantage is the need to always remember to allocate/free memory for C strings; working with fixed size buffers almost inevitably leads to buffer overflows. At last, C++ has a standard string class (std::string). So why the need for wxString?

いくつかの利点がある :

  1. 効率 このクラスは出来る限り効率的に作られた:サイズ(それぞれのwxStringオブジェクトはchar * ポインターとまったく同じスペースをとり、参照のカウントをたれこむ(訳?))と速度の両方において。また、 あなたの特定のアプリケーションのメモリ割り当て方法の調整に使用可能かもしれない、パフォーマンス統計収集コードを提供する - そして利益は大きいかもしれない。
  2. 互換性 このクラスは、wxWidgets 1.xx wxStringクラスとの最高にちかい互換性、MFC CStringクラスの若干の面影、そしてstd::stringクラスの90%の機能を兼ね備えるよう努める。
  3. 豊富な関数セット wxStringにある機能のうちのいくつかは非常に有用であるが、ほとんどの他の文字列クラスには存在しない : 例えば、AfterFirstBeforeLast<< 演算子、あるいはPrintf。もちろん、全ての標準的文字列操作は同様にサポートされる。
  4. Unicode wxStringはUnicodeフレンドリーだ : wxStringはどのビルドモードでも(詳しくはUnicode overviewを参照のこと)容易にUnicodeかASCIIの文字列に変換できる.そしてビルドモードに応じてstringwstringのどちらかに自動的にマップする.
    訳注:Unicodeモードならwstringに,非Unicodeモードならstringに,自動的に対応する
  5. wxWidgetsによって使用される そして、当然、このクラスはwxWidgets内部の至る所で使用されるので、wxWidgets内部での、他の文字列クラス(std:stringを含む)からwxStringへの変換に起因するパフォーマンス低下がない。

There are several advantages:

  1. Efficiency This class was made to be as efficient as possible: both in terms of size (each wxString objects takes exactly the same space as a char * pointer, sing reference counting) and speed. It also provides performance statistics gathering code which may be enabled to fine tune the memory allocation strategy for your particular application - and the gain might be quite big.
  2. Compatibility This class tries to combine almost full compatibility with the old wxWidgets 1.xx wxString class, some reminiscence to MFC CString class and 90% of the functionality of std::string class.
  3. Rich set of functions Some of the functions present in wxString are very useful but don't exist in most of other string classes: for example, AfterFirst, BeforeLast, operator<< or Printf. Of course, all the standard string operations are supported as well.
  4. Unicode wxString is Unicode friendly: it allows to easily convert to and from ANSI and Unicode strings in any build mode (see the Unicode overview for more details) and maps to either string or wstring transparently depending on the current mode.
  5. Used by wxWidgets And, of course, this class is used everywhere inside wxWidgets so there is no performance loss which would result from conversions of objects of any other string class (including std::string) to wxString internally by wxWidgets.

しかしながら、同様にいくつかの問題もある。最も重要な問題の一つは恐らく、全く同じことをする関数が複数存在する事だ : 例えば、文字列の長さを得るためにlength()、Len()Length()の何れが使われてもよい。最初の関数は、他のほとんど全ての小文字の関数と同様に、std::string互換である。二番目の関数は、wxStringネイティブであり、最後のものはwxWidgets 1.xx の方法である。そして問題は : どれを使うのがベターか? そして答えは :

std:string互換関数の利用が強く推奨される! それは、あなたのコードを他のC++プログラマ(std::stringについての知識はあるが、wxStringの知識はないと想定される)にとってより見慣れたものにするだろうし、 あなたがwxWidgetsと他のプログラムの両方の中で同じコードを共有できるようにする(wxWidgets以外のプログラムでは、 単にwxStringをstd::stringとtypedefすればよい)、そして遅かれ早かれstd::stringを使い始めるであろうwxWidgetsの将来の バージョンとの互換性を保つ.

対応するstd::stringの関数がない場合、どうか、軽視され、そして将来のバージョンで姿を消すかもしれない、古いwxWidgets 1.xx バージョンではなく、新しいwxStringのメソッドを使うようにして下さい。

However, there are several problems as well. The most important one is probably that there are often several functions to do exactly the same thing: for example, to get the length of the string either one of length(), Len() or Length() may be used. The first function, as almost all the other functions in lowercase, is std::string compatible. The second one is "native" wxString version and the last one is wxWidgets 1.xx way. So the question is: which one is better to use? And the answer is that:

The usage of std::string compatible functions is strongly advised! It will both make your code more familiar to other C++ programmers (who are supposed to have knowledge of std::string but not of wxString), let you reuse the same code in both wxWidgets and other programs (by just typedefing wxString as std::string when used outside wxWidgets) and by staying compatible with future versions of wxWidgets which will probably start using std::string sooner or later too.

In the situations where there is no corresponding std::string function, please try to use the new wxString methods and not the old wxWidgets 1.xx variants which are deprecated and may disappear in future versions.


wxStringを使う上でのアドバイス Some advice about using wxString

多分,このクラスを使う時の主な問題はconst char *への暗黙型変換であろう. 変換が行われている事を明確にするため,c_str()を用いることを推奨する. 暗黙型変換の危険性はこのコードに明確に見られる.
Probably the main trap with using this class is the implicit conversion operator to const char *. It is advised that you use c_str() instead to clearly indicate when the conversion is done. Specifically, the danger of this implicit conversion may be seen in the following code fragment:

// この関数はinput文字列を大文字に変換したoutput文字列を作成し,それを画面に出力してから返す.
// this function converts the input string to uppercase, output it to the screen // and returns the result
const char *SayHELLO(const wxString& input) { wxString output = input.Upper(); printf("Hello, %s!\n", output); return output; }
この3行に2つのいやらしいバグが存在する. 1つ目はprintf()関数の呼び出しの中にある. C言語タイプ文字列への暗黙型変換は↓ケースでは自動的に行われる.
There are two nasty bugs in these three lines. First of them is in the call to the printf() function. Although the implicit conversion to C strings is applied automatically by the compiler in the case of

    puts(output);
なぜならputs()の引数の型はconst char *だと判っているからだ. printf()は複数・多種類の引数を受け取るので,この暗黙型変換は行われない. よってこの実行結果は不定であり,正しく画面に出力するかもしれないし,クラッシュするかもしれない. 解決法は,単にこのようにc_str()に置き換える事だ.
because the argument of puts() is known to be of the type const char *, this is not done for printf() which is a function with variable number of arguments (and whose arguments are of unknown types). So this call may do anything at all (including displaying the correct string on screen), although the most likely result is a program crash. The solution is to use c_str(): just replace this line with

    printf("Hello, %s!\n", output.c_str());
2つ目のバグはoutputのreturnが働かない事だ. 暗黙型変換が行われるようにコンパイルされるが,関数が終了すると同時に破棄される変数に属する バッファへのポインタが返されるため,実行結果は不定である. この解決法も簡単である.関数がC言語タイプ文字列の代わりにwxStringを返すようにすれば良い.
The second bug is that returning output doesn't work. The implicit cast is used again, so the code compiles, but as it returns a pointer to a buffer belonging to a local variable which is deleted as soon as the function exits, its contents is totally arbitrary. The solution to this problem is also easy: just make the function return wxString instead of a C string.

このことは次の一般的な助言を導く:全ての文字列を引数に取る関数は,const wxString&を 取る(これは関数内への文字列の割り当てを高速にする. reference countingを参照) べきであり,全ての文字列を返す関数はwxStringを返す(これはローカル変数を 安全に返す)べきである.
This leads us to the following general advice: all functions taking string arguments should take const wxString& (this makes assignment to the strings inside the function faster because of reference counting) and all functions returning strings should return wxString - this makes it safe to return local variables.


その他の文字列に関した関数とクラス Other string related functions and classes

多くのプログラムは文字列を使用し,標準Cライブラリはかなりの数の文字列に関する関数を提供する. 不幸な事に,それらの関数のいくつかは直感できでない動作をする.(例えば,strncpy()がコピーした 文字列がNULL文字で終わるとは限らない)そして大概,あまり安全ではない.(それらの関数にNULLを渡したら, プログラムがクラッシュするかもしれない) それに加えて,幾つかのとても便利な関数は標準でない事もある. これが,wxString関数に加えて,幾つかのグローバル関数が以下の問題を解決するために用意された理由である: wxIsEmpty()は文字列が空かどうかを判定する(NULLポインタを 渡されたらTRUEを返す). wxStrlen()もNULLが渡されたら0を返す. wxStricmp()は単にプラットフォームから独立した大文字/小文字を区別しない 文字列比較であり,プラットフォーム依存のstricmp(),strcasecmp()として知られている関数と同じである.
As most programs use character strings, the standard C library provides quite a few functions to work with them. Unfortunately, some of them have rather counter-intuitive behaviour (like strncpy() which doesn't always terminate the resulting string with a NULL) and are in general not very safe (passing NULL to them will probably lead to program crash). Moreover, some very useful functions are not standard at all. This is why in addition to all wxString functions, there are also a few global string functions which try to correct these problems: wxIsEmpty() verifies whether the string is empty (returning TRUE for NULL pointers), wxStrlen() also handles NULLs correctly and returns 0 for them and wxStricmp() is just a platform-independent version of case-insensitive string comparison function known either as stricmp() or strcasecmp() on different platforms.

<wx/string.h>ヘッダはwxSnprintfwxVsnprintfを宣言する.これらはsprintf()snprintf()の代わりとして用いられ,可能な限りのバッファサイズのチェックをする. もちろん,wxString::Printfも同じく安全に用いることができる.
The <wx/string.h> header also defines wxSnprintf and wxVsnprintf functions which should be used instead of the inherently dangerous standard sprintf() and which use snprintf() instead which does buffer size checks whenever possible. Of course, you may also use wxString::Printf which is also safe.

他にも,wxStringと共に用いる便利なクラスwxStringTokenizerがある. これは文字列をトークンに分解する時に役立ち,標準Cライブラリのstrtok()関数を置き換える.
There is another class which might be useful when working with wxString: wxStringTokenizer. It is helpful when a string must be broken into tokens and replaces the standard C library strtok() function.

最後の文字列に関するクラスは,wxArrayStringである. これは文字列専用バージョンの動的配列である. このクラスは(格納しているのがwxStringであるという前提を用いて)特別に最適化されていて,ただの wxStringのwxObjectArrayよりも断然パフォーマンス面で優れいていることに注意して欲しい.
And the very last string-related class is wxArrayString: it is just a version of the "template" dynamic array class which is specialized to work with strings. Please note that this class is specially optimized (using its knowledge of the internal structure of wxString) for storing strings and so it is vastly better from a performance point of view than a wxObjectArray of wxStrings.


参照カウントと,それを開発者が気にしないで良い理由 Reference counting and why you shouldn't care about it

wxStringクラスはcopy on write (COW)として知られているテクニックを用いている. これはある文字列が別のオブジェクトに割り当てられた時,実際のコピーは行われず,リファレンス カウントがインクリメントされ,2つのオブジェクトは同じ文字列データを共有するだけである 事を意味する.
wxString objects use a technique known as copy on write (COW). This means that when a string is assigned to another, no copying really takes place: only the reference count on the shared string data is incremented and both strings share the same data.

しかし同じ文字列を共用している複数のオブジェクトのうち一つが変更されるとき,文字列は コピーされ他のオブジェクトには影響しない. データのコピーは文字列が書き込まれる時にしか行われない,これがCOWとして知られているものである.
But as soon as one of the two (or more) strings is modified, the data has to be copied because the changes to one of the strings shouldn't be seen in the others. As data copying only happens when the string is written to, this is known as COW.

理解しておかないといけない重要な事は,これらの全ての事はクラスのユーザーに対して 完全に透過的(ユーザーに意識されず)に行われる事と,文字列が共有されているかいないかは クラスの外からは関係なく,全ての処理の結果がどんな場合も同じになることだ.
What is important to understand is that all this happens absolutely transparently to the class users and that whether a string is shared or not is not seen from the outside of the class - in any case, the result of any operation on it is the same.

多分,開発者が参照カウントについて考えたくなる唯一のケースは,非const(もしくはconst参照)の 文字列から文字を取り出すときであろう. このケースでは,C++のルールにより,読み込み専用のoperator[] (GetChar()と同じ) は選ばれず,読み書き可能なoperator[] (GetWritableChar())と同じ) が代わりに用いられる. この演算子は文字列を変更できるので,コピーが行われる.そしてそれが共有されていた文字列なら, パフォーマンス(時間とメモリ使用量の両方で)のロスが生じる. このまれなケースでは,GetChar()を前述の理由で用いる 方が良い.at()関数も同じ問題を抱えているので,この関数を 使うのはあまり良くないということに注意して欲しい. また,全ての文字列引数をconst wxString&(Some advice を参照)としてとる関数では,このような状況は殆ど全く生じない(const参照からはconst演算子が自動的に 呼ばれるから)ことも覚えておくと良い.
Probably the unique case when you might want to think about reference counting is when a string character is taken from a string which is not a constant (or a constant reference). In this case, due to C++ rules, the "read-only" operator[] (which is the same as GetChar()) cannot be chosen and the "read/write" operator[] (the same as GetWritableChar()) is used instead. As the call to this operator may modify the string, its data is unshared (COW is done) and so if the string was really shared there is some performance loss (both in terms of speed and memory consumption). In the rare cases when this may be important, you might prefer using GetChar() instead of the array subscript operator for this reasons. Please note that at() method has the same problem as the subscript operator in this situation and so using it is not really better. Also note that if all string arguments to your functions are passed as const wxString& (see the section Some advice) this situation will almost never arise because for constant references the correct operator is called automatically.


あなたのアプリケーションのためのwxStringのチューニング Tuning wxString for your application


注意:このセクションは性能に関することだけを扱い,wxStringクラスを利用するために 読む必用は無い. プロファイラや関連したツールに慣れ親しんだ人以外は読み飛ばしてください. もしこのセクションを読むのなら,先に書いた参照カウント についてのセクションも読んでください.
Note: this section is strictly about performance issues and is absolutely not necessary to read for using wxString class. Please skip it unless you feel familiar with profilers and relative tools. If you do read it, please also read the preceding section about reference counting.

性能のために,wxStringは各々の文字列に,必用な量と同じ量のメモリを確保しません. そうではなく,必要とされるより少し多くのメモリを確保し,頻繁に再確保が行われないようにします. 例えば,下の例で示されるように,構築された文字列にあとから文字が追加されたるような時:
For the performance reasons wxString doesn't allocate exactly the amount of memory needed for each string. Instead, it adds a small amount of space to each allocated block which allows it to not reallocate memory (a relatively expensive operation) too often as when, for example, a string is constructed by subsequently adding one character at a time to it, as for example in:

// 全ての母音を文字列から削除する
// delete all vowels from the string
wxString DeleteAllVowels(const wxString& original) { wxString result; size_t len = original.length(); for ( size_t n = 0; n < len; n++ ) { if ( strchr("aeuio", tolower(original[n])) == NULL ) result += original[n]; } return result; }
このような状況はとてもよく起こり,余分なメモリを確保していなかったらとても性能が低下する. なぜなら元の文字列の中の子音の数と同じだけのメモリの再確保が起こるからだ. 必要以上なメモリの確保は,この状況では速度の向上に役立つ. しかし,大量のwxStringが使われるアプリケーションでは,メモリを大量に消費する事になってしまう.
This is quite a common situation and not allocating extra memory at all would lead to very bad performance in this case because there would be as many memory (re)allocations as there are consonants in the original string. Allocating too much extra memory would help to improve the speed in this situation, but due to a great number of wxString objects typically used in a program would also increase the memory consumption too much.

この(上のサンプル関数の)場合確実に最も良い方法は,Alloc()関数を 用いてメモリをpreallocateすることだ. 例えば,lenバイトのメモリをpreallocateすれば,メモリ確保は一回のみで済む. (最大でも元の文字列と同じ大きさにしかならないから)

The very best solution in precisely this case would be to use Alloc() function to preallocate, for example, len bytes from the beginning - this will lead to exactly one memory allocation being performed (because the result is at most as long as the original string).

しかしながら,Alloc()を使うのはめんどくさいし,wxStringは(Alloc()を使わなくても)ベストを尽くす. デフォルトのアルゴリズムでは,最低16バイトの粒度のメモリが確保される(広く使われている 殆どのプラットフォームではそうなっている)と仮定する.だから16の倍数に繰り上げたメモリを確保しても 全く無駄が生じない. このように,全く無駄にメモリを消費する事が無く,上の例では16文字毎に15回はメモリの割り当てが行われ ずに,使っていないメモリを用いる.
However, using Alloc() is tedious and so wxString tries to do its best. The default algorithm assumes that memory allocation is done in granularity of at least 16 bytes (which is the case on almost all of wide-spread platforms) and so nothing is lost if the amount of memory to allocate is rounded up to the next multiple of 16. Like this, no memory is lost and 15 iterations from 16 in the example above won't allocate memory but use the already allocated pool.

デフォルトの方法は全く保守的である. メモリの余分な確保は,(比較的に)とても長い幾つかの文字列を使うプログラムに大きなパフォーマンスの向上をもたらす. 確保するメモリの量は,string.cppファイルの中のEXTRA_ALLOCによって,コンパイル時に決まる. (この値を変えるときは,デフォルト値が何故使われいてるのかを確実に理解する事) 開発者はこの値をより大きい値(例えばnLenの倍)か0(それによる速度低下を知るため)に設定して, 自分のプログラムに与える影響を調査するかもしれない. もしそうするなら,wxStringクラスにパフォーマンスの統計を集めさせ,それをプログラム 終了時にstderrに出力するように支持するWXSTRING_STATISTICSを宣言すると役に立つだろう. これはプログラムが扱う文字列の平均長,初期の長さ,文字列の連結が行われた時にメモリの再確保が 行われずにすんだ割合(この値はデフォルトのポリシーでは約98%であるべきである.もしこれが90%未満 なら,開発者はそのアプリケーションの為にwxStringのチューニングを考えるべきである)を表示する.
The default approach is quite conservative. Allocating more memory may bring important performance benefits for programs using (relatively) few very long strings. The amount of memory allocated is configured by the setting of EXTRA_ALLOC in the file string.cpp during compilation (be sure to understand why its default value is what it is before modifying it!). You may try setting it to greater amount (say twice nLen) or to 0 (to see performance degradation which will follow) and analyse the impact of it on your program. If you do it, you will probably find it helpful to also define WXSTRING_STATISTICS symbol which tells the wxString class to collect performance statistics and to show them on stderr on program termination. This will show you the average length of strings your program manipulates, their average initial length and also the percent of times when memory wasn't reallocated when string concatenation was done but the already preallocated memory was used (this value should be about 98% for the default allocation policy, if it is less than 90% you should really consider fine tuning wxString for your application).

言うまでもなく,EXTRA_ALLOCの値の変更がプログラムに与える影響を 正確に測るためにプロファイラを用いるべきである.
It goes without saying that a profiler should be used to measure the precise difference the change to EXTRA_ALLOC makes to your program.