[SOLVED] Signal parameter of type std::unique_ptr

  • Is it possible to use a std::unique_ptr in a signal? I'm trying to embrace the new language features of C++11 and have been using unique_ptr and shared_ptr where possible.

    Now I want to emit a signal of the form:
    @void newThing(std::unique_ptr<Thing> thing);@

    When I emit the signal, I do it like this:
    @auto newThing = std::unique_ptr<Thing>(new Thing());
    emit newThing(std::move(newThing));@

    I get compiler errors in the moc file, so I'm wondering if I'm on a wild goose chase here that Qt 4.8.5 at least doesn't support this.

  • You need to register the type so that moc knows what it is.


    So in your case you need to declare


    in a header file and call @qRegisterMetaType<std::unique_ptr<Thing>>();@ before your signal and slots are used.

    By the way, Qt 4.8.5 is compiled with GCC 4.4 which does not support all C++11 features just so you know (unless you compiled Qt yourself of course :))

  • Thanks t3685!

    I've seen references to Q_DECLARE_METATYPE but I understood it to only be required when using a queued connection. Thanks for pointing me in the right direction.

    I have to support Windows and Linux and have been developing on Linux so far. I discovered that I couldn't compile my code using C++ features on Windows because the Qt SDK installed GCC 4.4, so I downloaded the latest MinGW Builds build which includes GCC 4.8.1. I rebuild Qt with this compiler. On Ubuntu 12.10 I'm using GCC 4.7 and I assume the Qt library was built with that version as well...

    Thanks for the help!

  • Now I get the same error on the Q_DECLARE_METATYPE line:
    @/usr/include/qt4/QtCore/qmetatype.h:142: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&)@

    I can't see how the meta type registration will have any influence, as I understand it is needed when transferring the parameter in a QVariant.

    Going back to the emit of the signal...

    The qt_static_metacall() method contains the following case:
    @case 1: _t->newThing((reinterpret_cast< std::unique_ptr<Thing>()>(_a[1]))@

    I suppose the problem is that the std::move is not used in the generated method call.

  • I've changed the parameter to std::shared_ptr, which works. At least I can make the code work, but I would still like too be able to use unique_ptr when it is the most appropriate smart pointer for the circumstance. So, I'm keeping it open.

  • From the documentation:

    "Creating a Custom Type Before we begin, we need to ensure that the custom type we are creating meets all the requirements imposed by QMetaType. In other words, it must provide:

    a public default constructor,
    a public copy constructor, and
    a public destructor."

    So your custom type (in this case std::unique_ptr) needs to meet those requirements. However, as you can see from your error that the copy constructor was "deleted" (google the C++11 keyword delete in header files).

    Which is logical if you think about it in hindsight :), when a signal is emitted, multiple slots can be connected to it: how can multiple slots have the same std::unique_ptr? I probably should have realized this before I pointed you to the documentation (my bad!).

    std::shared_ptr works because well, it can be shared :).

  • I missed the simple issue of sending the unique_ptr to multiple destinations completely! In my case I was thinking of the single slot provider and didn't think of the implications of having multiple slots breaking the unique_ptr contract! Hey, that's how you learn...


Log in to reply