考えるのをやめて観察する

FOGAプロジェクトをやっているとき、このルールを何回も反省している。

例1 Cのポインターをデバッグ

FOGAでは、学習モデルの入力と出力との関数を作った。
void readModel(string filename, StrMap* strmap, Label* label) {
//...
}

void saveModel(string filename, StrMap* strmap, Label* label) {
//...
}

int main(int argc, char* argv[]) {
 StrMap* strmap = new StrMap;
 Label* labelmap = new Label;
 readModel("model.txt", strmap, labelmap);
 saveModel("model_.txt", strmap, labelmap);
 return 0;
}


デバッグのために、model.txtというファイルからモデルを入力して(readModel)、また、そのモデルをそのままmodel_.txtに出力する(saveModel)。
そして、model.txtとmodel_.txtを比較する。
model.txt
31
,  3
, cho  10
VH   4
VH  VT   11
VT   2
VT  VH   9
(省略)

残念だが、全然違う。
model_.txt
0
0
0

最初では、saveModel()をデバッグする。 
void saveModel(string filename, StrMap* strmap, Label* label) {
     int tempint;
     tempint = static_cast<int> (strmap -> size());
     ofstream ofs(filename.c_str());

     ofs << tempint << endl;
     map<string, int>::iterator it, strmap_end = strmap -> end();
     int count = 0;
     for(it = strmap -> begin(); it != strmap_end; ++it) {
          ++count;
          ofs << it -> first << " " << it -> second << endl;
     }
     ofs << count << endl;

     tempint = static_cast<int> (label -> size());
     ofs << tempint << endl;
     it = label -> begin();
     strmap_end = label -> end();
     for(; it != strmap_end; ++it) {
          ofs << it -> first << "  " << it -> second << endl;
     }

 // write model

 ofs.close();
}

予想とおり出力したので、問題ないと思う。

したがって、readModel()では、問題ある。
void readModel(string filename, StrMap* strmap, Label* label) {
     int tempint, N;
     string tempstr;
     strmap = new StrMap;
     label = new Label;

     ifstream ifs(filename.c_str());
     ifs >> N;
     getline(ifs, tempstr);
     for(int i = 0; i < N; ++i) {
          getline(ifs, tempstr);
          strint(&tempstr, &tempint, &tempstr); //文字列から、数値とサブ文字列を取る
          strmap -> insert(pair<string, int>(tempstr, tempint));
     }
     ifs >> N;
     getline(ifs, tempstr);
     for(int i = 0; i < N; ++i) {
          getline(ifs, tempstr);
          strint(&tempstr, &tempint, &tempstr); //文字列から、数値とサブ文字列を取る
          label -> insert(pair<string, int>(tempstr, tempint) );
     }
}


私はポインターを誤用したかと思ったが、コードがバッグない。ロジックのバッグか?

考えるのをやめて観察する。
model_.txtを見ると、strmapとlabelの中身がないとわかる。
step-by-stepでデバッグすると、readModel()の中で、strmapとlabelをきちんと侵入できたが、main()に行ったら、全部なくなった。
したがって、ポインターのアドレスを渡さないか?違うアドレスを渡したか?

実は、後者の原因だ。

readModel()の中身には、初期化のために、
    strmap = new StrMap;
    label = new Label;
を書いた。しかし、'new'を使ったら、新しいアドレスを作って、ポインターに渡した。より、readModelの中身に扱うポインターはmain()に扱うポインターと違う。

結論:
変数、出力などを観察して、起こった事象を理解する。それの上で、ロジックのバッグを探す。
Comments