2017-04-13 10 views
0

デストラクタは、同じ(メイン)スレッドですべてが起きたときにUIウィンドウがキャンセルされたために、デストラクタが突然存在しなくなってしまっていると言っても意味がありますか?デストラクタが終了するのに時間が足りませんか?

私はダイアログで「キャンセル」を押すと、私はリストの時間に関連付けられたメモリを解放したい:

CMyListCtrl::~CMyListCtrl() 
{ 
    ItemData* pItemData; 
    int nItems = GetItemCount(); <- errors out here and it is called 
    for(int i=0; i<nItems; i++) 
    { 
     pItemData = (ItemData*)GetItemData(i); 
     if(pItemData != NULL) 
      delete pItemData; 
    } 
} 

マイOnCancel()ハンドラが

LONG CSetupDlg::OnCancel(UINT wParam, LONG lParam) 
{ 
    ((CSetupDoc *)GetActiveDocument())->Exit(); 
    return 0; 
} 

void CSetupDoc::Exit() 
{ 
    GetDocTemplate()->CloseAllDocuments(TRUE); 
} 

デストラクタ以下れます基本的にCloseAllDocuments()コールのために呼び出されますが、クリーンアップしようとしているときに途中で吹き飛ばされてしまいます。私がCloseAllDocuments()を呼び出すと、ウィンドウは決して破棄されず、デストラクタは決して呼び出されないので、デストラクタは確実にこの関数に結び付けられており、明らかに同じスレッド内にあります。

なぜ、基本的なウィンドウが魔法のように消えたかのようにアサーションしますか?

私が受け取るエラーメッセージはMyApp has triggered a breakpointであり、それ以上は何も実行できません。

+0

もっとコードを入力してください。実行されているすべての行を見ることなく、デバッグするのは難しいです。 – UniversE

+0

あなたが作業していることを(少なくともタグの中に)示してください。それはほぼ確実にWindowsですが、その後どのような環境ですか? MFC? ATL? –

+1

デストラクタはウィンドウが破棄されるまで呼び出されないと思うので、コントロールにアクセスするには遅すぎます。私はなぜこれが 'CloseAllDocuments'と結びついているのか分かりません。 –

答えて

1

問題を修正した正解を投稿しています。 LVN_DELETEITEMメッセージハンドラのリストメモリを解放する必要があります(OnDestroy()も機能しませんでしたが、その時点でリストはすでに消えています)。 GetItemCount()リストウィンドウ上で動作するが、それは既に破棄されているため、動作が不明であるため限りデストラクタがさらに実行していない/主張したとして

void CMyListCtrl::OnLvnDeleteitem(NMHDR *pNMHDR, LRESULT *pResult) 
{ 
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); 
    // TODO: Add your control notification handler code here 

    ItemData* pItemData = (ItemData*)pNMLV->lParam; 
    delete pItemData; 

    *pResult = 0; 
} 

です。

2

デストラクタ内からリストコントロールの機能にアクセスできないようです。私はこれがルールであるのか、それともあなたのコード内の他の奇妙な状況のために起こっているのかを覚えていません。原則として、あなたはそれを行うことはできません。

いずれにしても、リストコントロールのデストラクタではなく、リストコントロールのWM_DESTROYメッセージのハンドラでクリーンアップを実行することをお勧めします。

+0

そのように思えますが、私はいつかこの行動をいつか戻ってきたと言いたいと思います。しかし、技術的には、コントロールがリストコントロールのデストラクタである場合でも、それは破壊されないはずです。 – zar

+1

zarが正しいです。あなたのクラスのクリーンアップで 'CMyListCtrl :: DestroyWindow'をオーバーライドし、クリーンアップが終了したら' CListCtrl :: DestroyWindow'を呼び出します。 'CWnd'オブジェクトはデータをカプセル化しますが、実際のウィンドウと等価ではないため、通常は有効なウィンドウを必要とするMFCデストラクタでは何もしません。 –

+1

あなたが追加する 'WM_DESTROY'ハンドラ関数にブレークポイントを置くことをお勧めします。ヒットしたら、データブレークポイント(Breakpoints Pane上)を作成します。この条件は 'listcontrol-> m_hWnd'の変更です。変数はnullになり、実行はそこで一時停止します。その後、それぞれの関連するステップに個別にステップを進めることができるので、プロセス全体がどのように起こっているかをもっと理解することができます。ところで、もしあなたが "それを踏みにじることができない"なら、あなたは彼が特有のシンボルをロードしていないかもしれません。 – sergiol

1

あなたは長時間待っています。デストラクタでは遅すぎます。その時点で、ウィンドウハンドル(m_hWnd)は無効になり、Windowsはウィンドウを破棄しました。リストコントロール内の項目はすべてこの時点で削除されています。他の人が指摘しているように、独自のCMyListCtrl :: OnDestroy()関数とON_WM_DESTROY()マクロをCMyListCtrlメッセージマップに追加します。クリーンアップコードをOnDestroy()関数に入れます。

+0

それを試しても、GetItemCount()はゼロを返していますが、ダイアログは既に消えてしまっていますので、リストはすでに破棄されているようです。 – zar

+0

ああ、今は覚えている、それはWM_DELETEITEMで削除する必要があります! – zar

+0

通常、私はあなたがそれをやっているようにしません。通常、コレクションはコントロールの存続期間外に存在します。その場合、SetItemDataPtr()を呼び出すと、インデックス、ポインタ、イテレータ、またはコントロールによってクリーンアップする必要のないコレクション内のアイテムへの参照を設定しています。 –

関連する問題