Coverityのクイズを見て思うこと

Coverityのブログで、CEDECで出題されていたバグクイズに関しての投稿がありました。
C++のソースから、バグを見つけるというクイズです。
クイズを自分で頑張りたい人はまずはリンク先を見てください。

[[問題編]](http://www.coverity.com/html_ja/blog/?x=entry:entry150902-051758)
[[解答編]](http://www.coverity.com/html_ja/blog/?x=entry:entry150911-112004)

以後、上記ブログの内容を読んだものとして進めます。

#第2問のもう一つの答え

第2問のクイズですが、もう一つの回答があります。
37行目でnewの返り値をチェックしてエラーとしていますが、newの失敗はstd::bad_allocの例外を投げます。
NULLを返す実装もありますが、標準的な動作としては「例外を投げる」が適切でしょう。

静的解析ツールですので、「newが失敗した場合、bad_allocの例外を返す事があります」ぐらいの警告がほしいですね。

#第1問の修正ポイント

第1問みたいにコーディングしてしまわないようにどうすればいいか、ということを考えます。
結論から言えば、C++を使うならC言語スタイルの配列は使わず、
C++にある std::array や std::vector を使いましょう。

配列を関数に渡す場合はポインタとして渡すしかありません。
第1問は配列であるものをポインタとして渡したがために型情報が失われたのが原因です。
つまり配列は配列として引数にするべきです。
std::array や std::vector であれば、その型のまま関数に渡すことができます。

calc_class_membersをstd::arrayを使ったものとして書き換えてみましょう。

```cpp
template <size_t N>
void calc_class_members(std::array<base_class, N> &b){
	int i = 0;
    for (auto &value : b){
		value.x = i;
		value.y = i;
		i++;
	}
}
```

これだと、std::array\<dervid_class\> は渡せず、エラーになります。
派生した配列も渡せるようにするなら、配列の中身も含めてテンプレート化しましょう。

```cpp
template<typename T, size_t N>
void calc_class_members(std::array<T, N> &b)
{
	int i = 0;
    for (auto &value : b){
		value.x = i;
		value.y = i;
		i++;
	}
}
```

面倒ならこういう何でも受け入れてしまう形もありますね。

```cpp
template<typename T>
void calc_class_members(T &b)
{
	int i = 0;
    for (auto &value : b){
		value.x = i;
		value.y = i;
		i++;
	}
}
```

#第2問の修正ポイント

今回の場合、defineを使っているので、void*にキャストする必要は全くありません。
もっと言えばdefineなんか使わず、テンプレートでカチッと処理しましょう。

```cpp
template<typename T>
SAFE_DELETE(T &t){
	delete t;
	t = NULL;
}
```

#void *に関する考察

void*ですが、C++ではC言語ほど使う機会はありません。

void*は元々持っていた型を消してしまいます。
今回のバグの原因は型が消えていることで、deleteに型を伝搬できないという問題が起きています。

##型を問わない変数としての使用

void*はどんなポインタでも受け取れる型として利用できます。
そういう利用方法がしたいなら、boost::anyというものがあります。
こちらはvoid*と違い、値であっても保持することが出来る上に、
型を保持しているので、目的の型が入っているかをチェックも出来ます。

色々便利なのですが、長くなるので今回は割愛します。

##コールバックの汎用引数としての使用

void*を使うケースとして、コールバック関数の引数があります。
DirectInput の EnumDevices がその例ですね。
こちらのLPVOIDというのがvoid*を指しています。(LPVOID = long pointer void)
[EnumDevices](https://msdn.microsoft.com/ja-jp/library/Cc351907.aspx)

簡略化したソースで、どういう利用をしているか見ていきましょう。

```cpp
#include <vector>
#include <iostream>
#include <vector>

/* ここからライブラリ */
class Data{
public:
	int id;
	Data(int id):id(id){}
};

typedef void (*CallBack)(const Data &d, void *) ;

void EnumId(CallBack callback, void *vptr){
	for (int i = 0; i < 10; i += 2){
		Data data(i);
		callback(data, vptr);
	}
}

/* ここまでライブラリ */

void  GetData(const Data &, void *vptr){
	std::vector<int> &vec = *static_cast<std::vector<int> *>(vptr);
	vec.push_back(d.id);
}

int main(){
	std::vector<int> vec;

	EnumId(&GetData, &vec);

	for (auto &v : vec){
		std::cout << v << std::endl;
	}
}
```

ライブラリ、という部分が予め用意されている部分です。
EnumIdでidのデータを順番に取得してはコールバック関数を呼び出す仕組みです。

今回はidのリストを vector<int> に入れていきたいので、
コールバック関数にvector<int>を渡したいです。

しかし、ライブラリ作成者はユーザーがどんな型の変数を引数に追加したいかわからないので、
void *を受け取って内部で使ってもらう、という形式になります。

C++では、関数ポインタではなく関数オブジェクトでコールバック関数を受け取れば、
この問題を解決できます。

```cpp
#include <vector>
#include <iostream>
#include <vector>
#include <functional>

/* ここからライブラリ */
class Data{
public:
	int id;
	Data(int id):id(id){}
};

typedef std::function<void (const Data &)> CallBack;

void EnumId(CallBack callback){
	for (int i = 0; i < 10; i += 2){
		Data data(i);
		callback(data);
	}
}

/* ここまでライブラリ */

void GetData(const Data &d, std::vector<int> &vec){
	vec.push_back(d.id);
}

int main(){
	std::vector<int> vec;

	EnumId(std::bind(&GetData, std::placeholders::_1, std::ref(vec) ) );
    // ラムダ式を使えばもっと簡単 GetDataも不要
    // EnumId( [&vec](const Data &d){vec.push_back(d.id);} );

	for (auto &v : vec){
		std::cout << v << std::endl;
	}
}
```

関数オブジェクトなら変数のキャプチャが可能なので、void*みたいなのを用意することもありません。
ライブラリ側の対応が必要なので今すぐ置き換えるのは難しいでしょうが、
C++11対応も進んでくれば、void*みたいな旧時代の遺産は使わなくてよくなるでしょう。


\# 余談ですが、CoverityはCのツールでC++のツールではない印象がありますね…。