LoginSignup
3
0

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-05-21

問題

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++ベースである以上この手の隙間的な問題はいろいろありそう
3
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0