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

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

新規登録して質問してみよう
ただいま回答率
85.49%
C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

C++

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

Qt Creator

Qt Creatorは、Qtアプリケーションを開発するための開発統合環境(IDE)です。

Q&A

解決済

3回答

4382閲覧

【Qt】クラスのデストラクタが走った後に、スロットが動き続けてしまう

tuyudaku

総合スコア75

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

C++

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

Qt Creator

Qt Creatorは、Qtアプリケーションを開発するための開発統合環境(IDE)です。

1グッド

1クリップ

投稿2019/09/05 12:53

編集2019/09/06 00:27

発生しているものとしては
Segmentation faultになるのですが

色々デバッグしている中で何とか分かったのは
デストラクタ後にデストラクタが走ったクラスのスロットが動作し続けてしまっています
恐らくデストラクタが走る前に動いていたスロットだと思うのですが
そのせいで破棄されたクラスのオブジェクトにアクセスしようとしてセグ落ちが発生しているのだと思います
ふわふわした情報で申し訳ありません...

クラスが破棄されると同時に、動作中のスロットも停止させることはできないのでしょうか?

よろしくお願いします

##追記
情報が少なく言葉足らずで申し訳ありません...
分かった情報などをまとめさせた頂きます

  • 該当スロットはデストラクタが走る前に、呼び出されたもの
  • 該当スロットではループの処理をしている、ループ中にデストラクタが走っています
  • ループ処理内ではQEventLoopQTimer::singleShotを使ったスリープを使って1秒間隔で処理するようにしてある(個人的にはコレが何か問題を起こしているのかと思っております)
  • 該当スロットのループ内とデストラクタにログを仕込みましたが、デストラクタのログ後にループのログが確認できているので、デストラクタ後にも動き続けていると判断しました
  • 回答に頂いたので、thisのアドレスをログで出力させたのですが、デストラクタ後に該当スロットループ内のログでセグ落ちが発生しました、破棄されたthisへのアクセスのせいだと思われるので、私が考えている問題は起きていると思われます
  • ループ内でローカル変数へのアクセスは問題が起きませんが、メンバ変数へのアクセスをするとセグ落ちが発生します

ここまで書いて、あることに気付いたのですが
そもそもセグ落ちしている関数はスロット内で呼ばれているprivateメンバ関数です...
実質スロットの処理ではあるとは思いますが一応情報だけでも...
また何か状況が変わらないかと思いemitで該当スロットとコネクトしてあるシグナルを呼び出していたところを、QTimer::singleShotで動作させてみたのですが状況は変わりませんでした

yuki23👍を押しています

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

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

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

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

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

guest

回答3

0

ベストアンサー

既に回答の通り、通常のQtの使い方をしている分には、オブジェクトの破棄後にそのオブジェクトのスロットが呼ばれる、ということはありえません。
もし発生しているとすれば、通常の使い方をしていないということです。例えば以下のような点に問題はありませんか?

  • 他のスレッドのオブジェクトが、該当のオブジェクトのポインタや参照を持っている(所有権管理違反)
  • 他のスレッドから AutoConnection を使わず DirectConnection でそのスロットにつないでいる
  • スロットをメンバー関数として直接呼んでいる
  • スレッドの止め方がマニュアル通りでない

また、運が良ければ、静的解析ツールや valgrind などのメモリ解析ツールを使うと手がかりが得られる場合もあります。


追記へ

要するにこういうことでしょうか?

SomeObject::slotA() { ……前の処理…… ループ { QEventLoop loop; connect(1秒の単発タイマー → loop の quit); loop.exec(); ……次の処理…… ← ここで発生 } }

「QEventLoop を使ってスリープする」というのは間違った使い方です。
QEventLoop を呼ぶと、スロットが実行中にも関わらず、同じスレッドに属するあらゆるオブジェクトのあらゆるスロットを呼ぶことが可能になってしまいます。この状況で SomeObject が delete されないように厳密に管理することは極めて困難です。「気をつけて設計すればいい」という問題ではありません。

基本的に QEventLoop をスロットの中で呼ぶのはNGだとお考え下さい。
もしチームで開発しているのでしたら、コーディング規約で禁止することをお勧めします。

正しくは、例えば次のようにします。

SomeObject::slotA() { ……前の処理…… connect(1秒の単発タイマー → slotB); return; } SomeObject::slotB() { ……次の処理…… if (必要であれば) { connect(1秒の単発タイマー → slotB); } }

このようにすればタイマーで待っている最中に this が delete されても問題ありません(少なくともセグフォが発生しないという点については)
なお、Qt 5 以降なので、スロットの代わりにラムダを使うこともできます。「ラムダとは何か?」から説明するのは大変なので、興味がお有りであればご自分でお調べ下さい。

投稿2019/09/05 23:01

編集2019/09/06 09:33
yuki23

総合スコア1448

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

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

tuyudaku

2019/09/06 00:31

>オブジェクトの破棄後にそのオブジェクトのスロットが呼ばれる 言葉足らずで申し訳ありません... 破棄後に呼ばれるのではなく、スロット処理中に破棄が起きてもスロットが動き続けている状態です
yuki23

2019/09/09 09:21

追記に反応がないですが、何かわからないところがありましたか?
tuyudaku

2019/09/10 10:17

>追記に反応がないですが、何かわからないところがありましたか? すみません、普通にサイトを見ていませんでした >「QEventLoop を使ってスリープする」というのは間違った使い方です。 Qt sleepと調べると沢山出てくるため、これが一般的だと思っていました... 情報ありがとうございます >もしチームで開発しているのでしたら、コーディング規約で禁止することをお勧めします。 その様にしたいと思います >正しくは、例えば次のようにします。 修正したソースは頂いた例のようになっています! 何とかたどり着いた答えが合っているみたいでよかったです! ラムダに関してはそれなりに利用して活用しています! 回答ありがとうございました!
guest

0

こんにちは。

QObject のインスタンスを delete する時にわざわざ disconnect する必要は無いそうです。
私もこの記述を信じて開発していますが、キューに並んでいるイベントがslot側のオブジェクト開放後に処理された経験はないです。

当該オブジェクトをdeleteする直前にそのアドレスをログに残し、当該スロットでも同様にthisのアドレスをログに残すことで、おっしゃる現象が発生しているのかどうか確認できると思います。

投稿2019/09/05 14:38

Chironian

総合スコア23272

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

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

tuyudaku

2019/09/06 00:30

>当該オブジェクトをdeleteする直前にそのアドレスをログに残し、当該スロットでも同様にthisのアドレスをログに残すことで、おっしゃる現象が発生しているのかどうか確認できると思います デストラクタ後にスロット内でのthisアドレスをログしようとしたところでセグ落ちが発生しました thisが破棄されているせいだとは思います
Chironian

2019/09/06 05:17

追記をみました。それはQtのシグナルースロット機構と無関係です。シグナルが発生したらスロットを呼び出すための機構に過ぎません。呼び出されたスロットがどのように動作するのかQtのシグナルースロット機構は何も関知しません。 スロットは一種のメンバ関数に過ぎません。そのメンバ関数実行中に、そのメンバが属するオブジェクトをdeleteしてはいけないのは当たり前ですね。これはプログラマの責任です。
tuyudaku

2019/09/06 07:35

>そのメンバが属するオブジェクトをdeleteしてはいけないのは当たり前ですね。これはプログラマの責任です。 なるほど、なんでそんな実装をしているんだ!ということですね... 途中で処理を中断してでもオブジェクトを破棄したい場合はどうすればいいでしょうか...
Chironian

2019/09/06 07:56

う~~ん、当たり前ですが、その処理を中断させてからdeleteすれば良いです。 このような中断処理はデッドロックしやすいので頭痛いのですが、慎重に設計するしかありません。
guest

0

質問の書き方がぼんやりしているため回答しづらいですが…。

Qt では、インスタンスのデストラクタが呼ばれた際に、そのオブジェクトのインスタンスへ接続されているシグナル・スロットは自動的に破棄されます。このため、通常であればそのような状況は起こらないはずです。

QObject::~QObject()

All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue. However, it is often safer to use deleteLater() rather than deleting a QObject subclass directly.

一度プロジェクトをクリーンビルドしてみて、それでも再現するようでしたら、どこかでメモリを破壊していたりしないかの確認をしてみてはいかがでしょうか。

投稿2019/09/05 14:20

tasuku.

総合スコア347

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

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

tuyudaku

2019/09/06 00:29

>一度プロジェクトをクリーンビルドしてみて それでも状況は変わりませんでした...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問