Seaside Laboratory

Posts

C++ で型推論 (auto) を使う際の注意点

C++11 で追加された型推論 (auto) を使うと長ったらしい iterator 宣言などを簡潔に書けることもあり、何でもかんでも auto で宣言したくなってしまうが、場面によっては今まで通りの型宣言をした方が良いケースもある。

数値

int や double など数値系の型は他の型と違い加算や減算が頻繁に行われるため、その際に発生した暗黙の型変換によってサイズや符号が変化し、いつの間にか意図しない型になっていることがある。

unsigned int uFoo = 1;
int nBar = 2;
int nSum = uFoo + nBar;           // int
auto nAutoSum = uFoo + nBar;      // unsigned int

明示的な型宣言をしているコードを auto に置き換えるときは特に注意が必要。

ポインター

const と auto を組み合わせた時の挙動は少々特殊で、ポインターを const で宣言しても const になっていないことがある。

int nFoo = 1;

const int* lpFoo = &nFoo;         // const int*
*lpFoo = 2;                       // エラー: 参照先が const なので書き込めない

const auto lpAutoFoo = &nFoo;     // int* const
*lpAutoFoo = 2;                   // OK: const なのはアドレスなので書き込める

宣言を const auto* にすれば意図した結果になる。

const auto* lpAutoFoo = &nFoo;    // const int*

これは非 const 値を const に変換するときに発生する問題なので、元の型宣言に const が含まれていれば auto だけでも問題ない。

const char* GetFoo()
{
    return "Foo";
}

auto lpszFoo = GetFoo();          // const char*

typedef

Visual Studio には変数の上にマウスカーソルを移動すると型情報を表示する機能があるので、auto を使う際にはこの機能を使って推論された型を確認しているが、typedef で宣言された型は typedef 名ではなく実際の型が表示されるため、元の型が何だったのか分からなくなることがある。

DWORD dwFoo = 1;                  // DWORD
auto dwAutoFoo = dwFoo;           // unsigned long

特に Win32 API は typedef を使った型が多いのでむやみに使わない方がいいかもしれない。