質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Boost

Boost (ブースト)は、C++の先駆的な開発者のコミュニティ、 またそのコミュニティによって公開されているオープンソースライブラリのことを指します。

Q&A

解決済

2回答

3399閲覧

MFC(VS2015) + boost::Logで終了時に例外が発生

PineMatsu

総合スコア3579

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Boost

Boost (ブースト)は、C++の先駆的な開発者のコミュニティ、 またそのコミュニティによって公開されているオープンソースライブラリのことを指します。

0グッド

0クリップ

投稿2016/02/01 08:37

編集2016/02/01 08:38

mfcアプリにboost::Logを組み込もうとしています。ログの保存などロギングに関する動作は問題ないのですが、アプリ終了時に一般保護例外が出てしまいます。(boostのバージョンは1.60.0)
例外が発生する箇所は、boostのsrw_lock.hppの

c++

1BOOST_FORCEINLINE VOID_ AcquireSRWLockExclusive(PSRWLOCK_ SRWLock) 2{ 3 ::AcquireSRWLockExclusive(reinterpret_cast< ::_RTL_SRWLOCK* >(SRWLock)); 4}

で、::AcquireSRWLockExclusiveでSRWLockが0xddddddddと不正なアドレスを示しているために一般保護例外になっているようなのです。Visual Studioの呼出履歴を見ると

c++

1LPCExplorer.exe!boost::detail::winapi::AcquireSRWLockExclusive(boost::detail::winapi::_RTL_SRWLOCK * SRWLock)82 C++ 2LPCExplorer.exe!boost::log::v2s_mt_nt6::aux::light_rw_mutex::lock()67 C++ 3LPCExplorer.exe!boost::log::v2s_mt_nt6::aux::exclusive_lock_guard<boost::log::v2s_mt_nt6::aux::light_rw_mutex>::exclusive_lock_guard<boost::log::v2s_mt_nt6::aux::light_rw_mutex>(boost::log::v2s_mt_nt6::aux::light_rw_mutex & m)102 C++ 4LPCExplorer.exe!boost::log::v2s_mt_nt6::core::remove_all_sinks()511 C++ 5

となっていて、終了時のboost.Logの後片付けで発生しているんだろうなぁまでは分かるんですが、それ以上はboost.Logの内部の仕組みをよく理解してないので追いきれてません。

どなたか、わかる方がいれば助かります。
ちなみに、ロガーはクラス化してあって、MFC以外のアプリ(Win32)では問題なく動作しています。

MFC + Boost.Logは無理なんでしょうかね?(MFCを辞めたいのは山々なんですが、このアプリをWin32で作りなおすのは時間とコストを考えると事実上不可能に近い・・・)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

こんにちは。ちょっと長くなるので、こちらから。

ソースを追いかけてみたのですが、私もyohhoyさんの見解に賛成です。

::AcquireSRWLockExclusiveでSRWLockが0xddddddddと不正なアドレスを示している

このSRWLockはlog\core\core.hpp内で定義されているcoreクラスの実体(m_impl)のメンバm_mutexです。
超絶ややこしくて読みそこなっているかも知れませんが、m_implはstaticに獲得されるシングルトンでした。
これは、main()関数終了後制御できないタイミングで自動的に解放されます。・・・①

そして、PineMatsuさんのロガークラスをMFCのクラス内で獲得/解放していた場合、MFCのインスタンスが解放されるタイミングで解放されます。
そのMFCのインスタンスがどこで獲得されているのか分かりませんが、もし、グローバル変数的にstaticに獲得されている場合、main()関数終了後の制御できないタイミングで解放されます。②

つまり、①→②の順序で解放された場合、②のタイミングでremove_all_sinks()が呼ばれますが、①にて既にm_implの実体が解放されているため、冒頭の例外が発生するのだと思います。

対策は、yohhoyさんの言う通り、下記が正解のように感じます。(私も実動作させたわけではないので確信まではないですが。)

単にmain関数終了直前にremove_all_sinks()呼び出しで良いかもしれません(実動作させたわけじゃないので自信ナシ)

なお、MFCのインスタンス解放処理内で、ロガークラスがboost::logを操作すると何か問題が起きる可能性を懸念します。デストラクタ内では後始末だけに限定し、ログを取るようなことはしない方がよいかもしれません。

投稿2016/02/02 03:59

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PineMatsu

2016/02/02 04:32

解析ありがとうございます。(よくあんなややこしいのを読めますね。尊敬します) ロガークラスはCWinAppを継承したクラスで保持しています。 yohhoyさんのコメントにも書きましたが、ExitInstance()でremove_all_sinks()を呼ぶようにしてやったら、メモリリークも含めてうまくいきました。 これで、Win32アプリとMFCアプリ両方で共通に使えるロガークラスが出来そうです。
guest

0

ベストアンサー

Boost.Logドキュメントに Why my application crashes on process termination when file sinks are used? という情報がありました。

MFCアプリケーション終了の直前に、下記コードを呼び出してみたらどうでしょう?

cpp

1logging::core::get()->remove_all_sinks();

投稿2016/02/01 15:14

yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PineMatsu

2016/02/02 00:01

remove_all_sinks()はクラスのデストラクタで呼び出していたのですが、呼出履歴にあるようにこのremove_all_sinks()の中で例外が起こっているようでした。 それで、ロガーのインスタンスをメインクラスのメンバーではなく、グローバルでポインターとして定義し、new,deleteで生成と破棄をメインの最初と最後に置くようにしたところ、例外は出なくなりました。 しかし、終了時にロガークラス内でsink追加した時に指定した日付指定文字列やベースファイル名などがメモリーリークするようになりました。むむむ・・・。 なんかもう少しのような気がするのですが・・・。
yohhoy

2016/02/02 02:08

今回の問題は、main関数を抜けた後にremove_all_sinks()が呼ばれたことが原因のように_見えます_。グローバルロガーを生ポインタ保持すると別の問題が出そうですし、単にmain関数終了直前にremove_all_sinks()呼び出しで良いかもしれません(実動作させたわけじゃないので自信ナシ) 参考:http://www.boost.org/doc/libs/1_60_0/libs/log/doc/html/log/rationale/init_term_support.html 「終了時のメモリリーク」はどのように検出されたのでしょう? プロセス終了時の内部メモリリーク(≠外部リソースのリーク)であれば実用上問題はありませんから、無視するという戦略もあります。
PineMatsu

2016/02/02 02:38

なるほど、ありがとうございます。デストラクタではなくremove_all_sinks()の積極的な呼び出しをやってみます。 メモリリークは、MFCで通常やっているやり方です。外部リソースではないので仰るとおり実用上は問題なさそうですね。
PineMatsu

2016/02/02 04:24

生ポインター保持をやめて、ExitInstance()でremove_all_sinks()を呼び出すようにしたら例外もメモリリークも発生しなくなりました。 ありがとうございました!助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問