none
ローカルクラスのデバッグ RRS feed

  • 質問

  • Visual C++ 2008 Express Edition で以下のように関数内にローカルクラスを定義し、コンストラクタにブレークポイントを置いてデバッグ実行したところ、自動変数ウィンドウにthisはアドレスのみ表示され、メンバ変数の"_n"が表示されません。

    ウォッチウィンドウに"_n"と入力すると、値の欄には"CXX0033: エラーです: OMF の型情報にエラーがあります "と表示されます。

     

    Code Snippet

    void Hoge()
    {
     class Local
     {
      int _n;
     public:
      Local(int n)
      {
       _n = n;
      }
      ~Local()
      {
       cout << _n << endl;
      }
     };
     Local local(100);
    }

     

     

    何か方法があるのでしょうか?

    よろしくお願いします。

    2008年2月21日 14:46

すべての返信

  • VS2005のC++でも症状は再現しています。

     

    たぶん、以下の記事に類似した現象のようですが、正確に該当しているのかどうか・・・確証なし。解決策のところも、まだ、上手くいくことを確認できていません。

    http://support.microsoft.com/kb/102697/en-us

     

    ----追記 確かに、関数の中にローカルにクラス定義を置いたときだけなわけですね・・・。以下なら、問題ナシ。

    Code Snippet

    class Local {
        int _n;
    public:
        Local(int n) {
            _n = n;}
        ~Local() {
            cout << _n << "\n";}
    };

    void Hoge() {
        Local local(100);
    }

     

     

     

     

     

     

     

    2008年2月22日 4:49
  • 回答ありがとうございます。

     

    提示していただきましたKBを見てました。プリコンパイル済みヘッダーにシンボルのデバッグ情報を明示的に埋め込む方法のようですが、今回の場合、ソース中に定義したクラスなのでプリコンパイル済みヘッダーは関係ないのではないかと思います。

     

    素直に関数の外にクラス定義を置いた方が無難みたいですね。

     

    2008年2月22日 6:31
  • 確かに、リンクした記事は、直接は該当しないかも・・・。ただ、開発環境の内部では何か関係があるのかなぁ、とも思いますが、想像の域を超えません。

     

    で、「素直に・・・」については、まぁ、回避策としては良いのですが、

     

    一般論としては、「ローカルにクラスを定義して使う」ということ自体は問題ない手法であって、これが容易にデバッグできないのは障害ではないかと・・・。フィードバックに上げてみられてはどうでしょう?

     

    -----(追記です。)

     

    呼び出し履歴を使って、呼び出し元に遡れば、オブジェクトのメンバー変数として値が読み取れますね。privateなメンバーであっても。

    2008年2月22日 7:19
  • この件に関して、外池さんのおっしゃるようにフィードバックにあげておきました。

     

     外池 さんからの引用

    呼び出し履歴を使って、呼び出し元に遡れば、オブジェクトのメンバー変数として値が読み取れますね。privateなメンバーであっても。

     

    実際のプログラムでは、以下のコードのような場合です。ローカルクラスは派生クラスであり、またクラスのインスタンスも関数を抜けても生きています。

     

    Code Snippet

    class UndoAction

    {

        ...

        virtual void Undo() = 0;
    };

     

    class UndoManager

    {

     

        ...

        bool Undo()
        {

            UndoAction* action;

            ...

            action->Undo();     // <= 呼び出し元

            return true;
        }

        ...

    private:

        vector<UndoAction*> _actions;

    };

     

    class Person
    {
        string _name;
    public:
        Person()
        {
        }
        string Name() const
        {

            return _name;
        }
        void Name(const string& name)
        {
            class NameUndoAction : public UndoAction
            {
                Person* _person;
                string _oldName;
                string _newName;
            public:
                NameUndoAction(Person* person, const string& newName)
                : _person(person), _oldName(person->_name), _newName(newName)
                {

                }
                virtual void Undo()
                {
                    _person->_name = _oldName;
                }
                virtual void Redo()
                {
                    _person->_name = _newName;
                }
            };

     

            if (name.compare(_name) == 0)
                return;

            UndoAction* action = new NameUndoAction(this, name);
            undoManager.Commit(action); // undoManagerはグローバルとします。

            _name = name;
        }
    };

     

     

    この場合、action->Undo(); の箇所ではNameUndoActionクラスが見えない(キャストできない)のでメンバ変数の値が見えません。
    2008年2月22日 16:28