トップ回答者
Windows7PCでVisualstudio2008のDebugモード実行時に、VC++で作成したXXXX.dllを呼出すとAccess Violation(0x000000005)が発生する。

質問
-
以下環境にて、掲題の現象が発生し、困っています。
どなたか対処方法について、ご教授お願い致します。
開発環境 OS Windows 7 x86 SP1 ツール Visual Studio 2008 SP1 DB MSSQL 2005 言語 VC++ 8.0 出力 XXXX.dll 追記 msado15.dllを使用 ① Windows XP環境ではDebug、Releaseモード共に正常に動作する
② Windows7のReleaseモード時は正常に動作する
③ ADOのレコードセットのClose()の後、レコードバインディングインタフェースのRelease()時に異常終了する 。//宣言を追記しました。
_RecordsetPtr m_targetRecordSet;
IADORecordBinding *m_targetIADOBinder;if( m_targetRecordSet != NULL ){ // DBにアクセスしていれば
m_targetRecordSet->Close(); // RecordSetを閉じる
m_targetRecordSet->Release(); // リソースを開放する
m_targetRecordSet = NULL ; // NULLにする
}
if (m_targetIADOBinder != NULL)
{
m_targetIADOBinder->Release(); ⇒ ■Access Violation発生
m_targetIADOBinder = NULL;
}
④ レコードセット及びレコードバインディングインタペースはポインターメンバー変数でクラス生成時に初期化されている
targetRecordSet = NULL ;
m_targetIADOBinder = NULL;
⑤ m_targetIADOBinderの値が異常値に変更される時点はレコードセットがNULLに変更される時点です
m_targetIADOBinderの参照アドレスが0xfeeefeeeになる
⑥ 今のmsado15.dllのバージョンは6.1.7601.17514である以上、宜しくお願いします。
- 編集済み _Te 2011年6月9日 3:53
回答
-
m_targetRecordSet がスマート ポインターなので、
m_targetRecordSet->Release(); // リソースを開放する m_targetRecordSet = NULL ; // NULLにする
これをやってはいけない気がします。
NULL を代入するところで、スマート ポインターが内部で保持しているインスタンスを Release しようとするはずですので、既に破棄されたインスタンスでもって Release してしまいます。
もしもやるなら、
m_targetRecordSet.Release();
なんでしょうけれど、スマート ポインターなので後始末はしない(スマート ポインターに任せる)というのではいかがでしょうか。
# Windows 7 の Release ビルドで動いてしまうのは、Debug ビルドと違って破棄された領域にゴミが入らないから運悪く動いているように見えるのでしょうけれど、
# Windows XP でも運悪く動いてしまっているのは、OS が違うからなのだろうか...。
-
totojoさんのおっしゃる通りで、m_targetRecordSetの定義を辿っていくと、スマートポインターの実体として_com_ptr_tクラスに行きつくと思います。このクラスのoperator=()を読むと、NULL代入などを行った際、元に保持していたポインターに対してRelease()を呼び出していることがわかると思います。
# とはいえ、operator=()のドキュメントにはそんなこと書かれていないのではまりやすいなぁ…
- 回答としてマーク 山本春海 2011年6月24日 8:51
-
基本は放っておいて構わないとおもうのですが、もしやるとしたら、
m_targetRecordSet = NULL ;
と NULL を代入するよりも
m_targetRecordSet.Relase();
とするべきだと思います。
NULL を代入すると内部で Release() されるっていうのは、スマート ポインターの実装にまで立ち入ってしまっているので、カプセル化の観点でイケてないように思います。
それに引き換え、後者のスマート ポインターの Release() はよく見かけるコーディングですので、驚き&疑いが少ないです。- 回答としてマーク 山本春海 2011年6月24日 8:51
すべての返信
-
m_targetRecordSet がスマート ポインターなので、
m_targetRecordSet->Release(); // リソースを開放する m_targetRecordSet = NULL ; // NULLにする
これをやってはいけない気がします。
NULL を代入するところで、スマート ポインターが内部で保持しているインスタンスを Release しようとするはずですので、既に破棄されたインスタンスでもって Release してしまいます。
もしもやるなら、
m_targetRecordSet.Release();
なんでしょうけれど、スマート ポインターなので後始末はしない(スマート ポインターに任せる)というのではいかがでしょうか。
# Windows 7 の Release ビルドで動いてしまうのは、Debug ビルドと違って破棄された領域にゴミが入らないから運悪く動いているように見えるのでしょうけれど、
# Windows XP でも運悪く動いてしまっているのは、OS が違うからなのだろうか...。
-
totojoさんのおっしゃる通りで、m_targetRecordSetの定義を辿っていくと、スマートポインターの実体として_com_ptr_tクラスに行きつくと思います。このクラスのoperator=()を読むと、NULL代入などを行った際、元に保持していたポインターに対してRelease()を呼び出していることがわかると思います。
# とはいえ、operator=()のドキュメントにはそんなこと書かれていないのではまりやすいなぁ…
- 回答としてマーク 山本春海 2011年6月24日 8:51
-
totojoさん、佐祐理さん お返事、ありがとうございます。
スマート ポインターですが、確かに佐祐理さんがおっしゃった通りに_com_ptr_tクラスのoperator=()で元に保持していたポインターに対してRelease()を呼び出していました。
スマート ポインターに対して詳しく分かりませんが、リソースの開放を内部でやってくれるみたいですね。
その意味で今のソースを軽くした方が良いということでしょうか?
例えば下のようにif( m_targetRecordSet != NULL ){ // DBにアクセスしていれば
m_targetRecordSet->Close(); // RecordSetを閉じる
m_targetRecordSet = NULL ; // NULLにする
}
if (m_targetIADOBinder != NULL)
{
m_targetIADOBinder = NULL;
}この場合、メモリリークの調査やWindows XPでの動作確認が必要になりますが上の順で問題なければ良いと思っています。
お返事、ありがとうございました。 -
基本は放っておいて構わないとおもうのですが、もしやるとしたら、
m_targetRecordSet = NULL ;
と NULL を代入するよりも
m_targetRecordSet.Relase();
とするべきだと思います。
NULL を代入すると内部で Release() されるっていうのは、スマート ポインターの実装にまで立ち入ってしまっているので、カプセル化の観点でイケてないように思います。
それに引き換え、後者のスマート ポインターの Release() はよく見かけるコーディングですので、驚き&疑いが少ないです。- 回答としてマーク 山本春海 2011年6月24日 8:51