Help us understand the problem. What is going on with this article?

QQuickImageProviderを使うとプログラム終了時に不正終了する問題

問題

QQuickImageProviderを使ったプログラムでは、main.cpp内での登録方法に気を付けないとプログラム終了時に謎のエラーに遭遇することがある。

参照 → Qtを使った簡単なGUIアプリ(1) マンデルブロー集合を描いてみる

QtCreatorから実行した場合、メインウインドウを閉じるとQtCreatorのApplication Outputペインにこんなエラーが出る

20:51:15: Starting C:\git\build-QtMandelbrot-Qt_5_14_1_msvc2017_64-Release\release\QtMandelbrot.exe ...
20:51:23: The program has unexpectedly finished.
20:51:23: The process was ended forcefully.
20:51:23: C:\git\build-QtMandelbrot-Qt_5_14_1_msvc2017_64-Release\release\QtMandelbrot.exe crashed.

プログラムの動作自体は正常なのでなかなか気づかなかったが、気持ち悪いので修正したい。

原因

問題の箇所

main.cpp
    FractalDrawer fractalDrawer(sizeSettings.getCanvasWidth(), sizeSettings.getCanvasHeight());
    QQmlApplicationEngine engine;
    engine.addImageProvider(QLatin1String("fractalDrawer"), &fractalDrawer);
    engine.rootContext()->setContextProperty("fractalDrawer", &fractalDrawer);
FractalDrawer.h
class FractalDrawer : public QObject, public QQuickImageProvider
{
  • QObjectの派生クラスは、スタック上にインスタンスを確保してもメモリの管理はQtがよろしくやってくれる
  • QQuickImageProviderQObjectの派生クラスではないので、addImageProvider()の引数としてアドレスを渡すと、エンジン終了時にdeleteされてしまう
  • 今回の例ではFractalDrawerQObjectからも多重継承されているが、addImageProvider()からはQQmlImageProviderBase型として扱われる
  • 結果、スタックに置いてあるにも関わらずエンジン終了時にdeleteされる
  • main()終了時にメモリ解放しようとして二重解放でエラー

修正方法

スタックに置くのをやめてヒープに置くようにした

main.cpp
    auto *fractalDrawer = new FractalDrawer(sizeSettings.getCanvasWidth(), sizeSettings.getCanvasHeight());
    QQmlApplicationEngine engine;
    engine.addImageProvider(QLatin1String("fractalDrawer"), fractalDrawer);
    engine.rootContext()->setContextProperty("fractalDrawer", fractalDrawer);

感想

  • 多重継承はやっぱりやめたほうがいいかもしれない
  • QObjectをC#や基本型の変数のように気楽に定義できるQtの世界観は好きなのだけど、やはりC++ベースである以上この手の隙間的な問題はいろいろありそう
y_uehara1011
歌って潜れる組み込み系エンジニア
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした