torutkのブログ

ソフトウェア・エンジニアのブログ

Visual Studio 2010でC++/ネイティブな開発

数年間C++から離れていたので、その間にWindows/C++に起きた技術の変化を追いかけて整理をしています。

とりあえず大枠として考えていることは次です。

  • 文字コードの扱い
  • C++ 11規格の扱い
  • 64bitコードの扱い
  • 並列処理の扱い
  • Boostライブラリの使用範囲
  • ロギング

文字コードの扱い

C++でプログラミングをする際に、文字列に日本語を使用する場合もワイド文字(文字をwchar_t型で扱う方式)を使わずマルチバイト文字(文字をchar型で扱う方式)を長らく使ってきました。Windows OSでは、char型のデータ1つまたは2つを用いてシフトJISWindows-31J)符号化した文字コードを保持します。

しかし、Windows Vista以降はOSの仕様としてJIS X 0213文字集合をサポートするようになり、Windows-31Jでは表現できない文字が存在します。よって、マルチバイト文字として文字データを扱うプログラミングでは困ったことになります。例えば、ユーザーがGUI上からテキストを入力し、その中にWindows-31Jで表現できない文字が含まれていた場合、そのテキストをchar型配列にマルチバイト文字(Windows-31J)で格納することができません。

Linux等のC++プログラミングでは、char型のデータにUTF-8符号化した文字コードを保持することが多いのですが、日本語Windowsではマルチバイト文字はWindows-31J決め打ちというライブラリが大半なので、それも難しいです。

ということで、Windows Vista以降のOS上で実行する日本語を扱うプログラムを開発するときは、ワイド文字を使うプログラミングをするのがよさそうです。

なお、Visual Studio 2010のC++では、プロジェクトウィザードで生成するとデフォルトで「Unicode文字セットを使用する」(ワイド文字)となっています。

C++11規格の扱い

Visual Stuido 2010では、2011年に承認されたISO/IEC 14882:2011規格(通称 C++11)で導入された仕様がいくつか実装されています。

この実装されたC++規格機能に対して、

  1. 積極的に使用する
  2. 使用してもよいがしなくてもよい
  3. 使用を禁ずる

という態度が考えられます。

3. については、ISO/IEC 14882:2003ないし1998規格で作成された既存コードの保守であれば合理的ですが、その場合コンパイラも当時のバージョンを使うべきです。Visual C++ 2010ではC++11規格が使えてしまいます*1

コンパイラのバージョンアップによって、コンパイルエラーが出ることが往々にしてあります。よりコンパイル検証が厳しくなって、前はコンパイルが通っていた(規格的にはまずい)コードも、新しいバージョンでエラーになることもあります。また、Visual Studioの場合、プロジェクトファイルがバージョンによって違うため、作り直しが必要になるといったことも考慮に入れる必要があります。

2.については、担当するプログラマー次第となるため、人によって作成したモジュールのAPIに素のポインタが使われたり、スマートポインタが使われたりと保守性(可読性、一貫性)が劣化してしまいます*2

ということで、1.として臨み、またその際担当するプログラマーが集まって学習する場を持つのがよさそうです。

64bitコードの扱い

昨今、32bitプロセスはメモリの壁に達することが出始めています。Windows OSの場合、32bitプロセスは4GBの仮想アドレス空間のうちOS用に2GBが取られるため、アプリケーションは残る2GBの空間しか利用できません。この2GB空間に、プログラムコード、スタック、ヒープ、共有メモリなどが押し込まれます。大量のデータを扱ったり、長期間稼働するようなプログラムは、64bitで作成するのがよさそうです。

逆に、クライアント用(や各種ツール)で動作するOSが64bitである保証がない場合、32bit版/64bit版の両方を生成するのは手間なので、32bitコードとして作成するのがよさそうです。

なお、Visual C++の64bitコード(LLP64モデル)は、UNIX系のGCC(LP64モデル)とlong型のサイズが異なります。

並列処理の扱い

マルチスレッドを使用する場合、C++11規格で導入されるはVisual C++ 2010では未実装なため、Windows APIC言語インタフェース)を使う必要があり、非常に低レベルなコーディングが必要になります。

これを補うには、ACEBoost.ThreadQtPocoTinyThread++などのC++用ライブラリを使う方法もあります。

ただ、多くのライブラリは大きなライブラリなので、スレッドのためだけに導入するのはためらわれます*3

一方、OpenMPVisual Studio 2010で用意されるParallel Pattern Libraryなどによる並列処理を使うと、局所的な処理の並列化ができます。

並列処理については、過渡期という状況と思われます。

Boostライブラリの使用範囲

Boostは、C++標準に欠けているさまざまな機能を提供するので、一度使うとはまってしまいます。

しかし、いいことずくしではなく、かならずしも互換性のないバージョンアップ、どんどん肥大化している、など負の面も考慮に入れる必要があります。

また、例えばスマートポインタなどC++11規格に取り込まれた機能とBoost側の同機能が混在するときに生じる問題と対処方法などについては分かっていないこともあります。

Boostライブラリは、使用するライブラリを制限して導入するのがよさそうです。ただし、その制限をどの範囲にするか調査・検討するのはかなり骨が折れそうです。

情報源

C++11標準スマートポインタとBoostスマートポインタの相互変換について言及しているブログを見つけました。

ロギングライブラリ

C++ロギングライブラリの候補については、以前に調査した内容を次のWebページに記述しました。

現在の主流は、Javaの定番ログライブラリlog4jC++移植版で、いくつか分派があります。機能的にはこれらのいずれかで十分かと思います。

ただし、C++のアプリケーションで、ログが原因で性能が満たせないケースに幾度となく直面してきたので、ログの性能に与える影響は大分気にしています。

性能に関する情報源へのリンクを以前の日記で書いています。

性能を考慮したロギングライブラリの調査・選択も課題です。

*1:コンパイルオプションで無効化できるかと思ったが見当たらない

*2:C++11以前でも、プログラミングした人によって思い切りC言語的な書き方からテンプレートを駆使したものになったりしていますが・・・

*3:TinyThread++は小さなライブラリ