【C++ boost】意外と面倒なboost::shared_ptrによるWindowsリソースの管理【C++】structとclassの関係

2013年03月11日

【C++全般】デフォルト引数に注意せよ

C++におけるデフォルト引数とは引数を省略したときに使われる値である。たとえば、

void Print(int i, int j = 0);
と宣言しておけば
Print(3);
と書いたときに暗黙に第二引数として0を渡してPrint(3, 0)と解釈してくれる。

一見便利なデフォルト引数であるが、コンストラクタに使うと思わぬ落とし穴にハマることがある。以下にコードを示す。

#include <iostream>
#include <string>
#include <boost/format.hpp>

//名前と値段を持つ「商品」
class Item{
public:
    Item(const char* name_, int value_ = 0) : name(name_), value(value_){}
    std::string GetName() const { return name; }
    int GetValue() const { return value; }
private:
    const std::string name;
    int value;
};

//商品の名前と値段を出力する
void PrintItem(const Item& item){
    std::cout << boost::format("%s : %d") % item.GetName() % item.GetValue() << std::endl;
}


int main(void)
{
    Item tsugaru("Tsugaru", 3000);
    PrintItem(tsugaru);
    //Tsugaru : 3000

    PrintItem("Jonathan");
    //=> Jonathan : 0

    return 0;
}

どうだろう?2個目のPrintItemには本来Itemを渡すべきところを間違って商品名を直接渡しているのがお分かりいただけると思う。しかもそれはコンパイルエラーにならず、実行時に値段が勝手に0に設定されて動き続けてしまうのだ。恐ろしい!

これは以前紹介した変換コンストラクタの仕業である。「え、引数が複数あるのに変換コンストラクタになるの!?」と思われるかもしれない。実はデフォルト値により引数が1つにまで省略可能なコンストラクタは変換コンストラクタとなりうるのである。これを防ぐにはやはりexplicitをつければよいのだが・・・

大人数で作業するときはそこまで意思疎通が徹底できるとも限らない。「あ、このコンストラクタの引数ほとんど使われてないな、省略できるようにしておこう」と誰かが不用意にデフォルト値を設定するかもしれない。コンパイラが警告してくれればよいが、なければ自前でツールを作るなりして自動的に警告が出るようにしておいたほうが良い。



dormolin at 21:22│Comments(0)TrackBack(0)C++ 

トラックバックURL

コメントする

名前
 
  絵文字
 
 
【C++ boost】意外と面倒なboost::shared_ptrによるWindowsリソースの管理【C++】structとclassの関係