vectorデータが壊れるのはなぜでしょうか?

解決


しょう  2012-10-06 17:07:06  No: 73530  IP: [192.*.*.*]

はじめまして。
いつも参考にさせて頂いておりますが、今回初質問です。

CSVファイルを読み込んでダイアログ上に配置したCListCtrlにCSVの内容を表示するMFCダイアログベースのアプリを作成しています。

CListCtrlには拡張スタイル(LVS_EX_CHECKBOXES)をセットしており、そのチェック状態をメンバ(vector<BOOL> m_vChk;)に保存しています。
(CSVファイルのデータは別のCString型のvector 2次元配列 m_vStrに保存している)

大まかな動きは以下の通りです。
-----
1.CSVファイルを読み込んでm_vStrに保存
2.m_vChkにm_vStrの行数分だけ要素を追加(デフォルトのため値は全行ともTRUE)
3.m_vStr、m_vChkの値をCListCtrlにInsertItem()、SetItem()して表示
------

上記のstep.3のm_vChkの値をCListCtrlにセットする処理
  for(int i = 0; i < m_vChk.size(); i++) {
    BOOL bCheck = m_vChk.at(i);
    CListCtrl.SetCheck(i, bCheck);  ←ここ
  }
の中の「←ここ」の行を実行直後にm_vChkのデータが壊れてしまいます。

具体的にはbCheckの値がTRUEでSetCheckした場合のみ
添え字iの次以降のすべての要素の値が-1など別な値になってしまいます。
(FALSEでSetCheckしても壊れない)

vectorを初めて使うものでお作法通りとなっていないかもしれません。
どなたかご存知の方、同じ状況になったことのある方、
アドバイス頂ければ幸いです。

よろしくお願いします。

編集 削除
しょう  2012-10-06 19:35:09  No: 73531  IP: [192.*.*.*]

自己解決しました。

メモリリークかSTLのワナかと思い静的コード解析など試しておりましたが、単純なバグでした。
お恥ずかしい限りです。

CListCtrl::SetCheckをしてもOnLvnItemchangedが発生するのですね。
CListCtrlのチェック状態の変化をOnLvnItemchangedで取得していましたが、その中で変化があったItemだけでなくすべてのItemのチェック状態をCListCtrlから取得してm_vChkにセットしていました。

そのためm_vChkの中でTRUEになっていたものもSetCheckする前の状態(FALSE)を取得してm_vChkに値をセットしてしまいFALSEになっていました。
(-1になったのは更にCListCtrlにSubItemを追加していない範囲までGetCheckしていたためでした)

この処理を
-----
  LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

  bool bOld = ((pNMLV->uOldState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2));
  bool bNew = ((pNMLV->uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2));

  if(bOld != bNew) {
    int iItem = pNMLV->iItem;
    m_vChk[iItem] = bNew;
  }
-----
とすることで、対象を変化があったItemのみとし、CListCtrlからチェック状態を取得せずにメッセージで飛んでくる正しい値をm_vChkにセットするようにしました。

編集 削除