将std :: unique_ptr作为带有std :: move的qt信号参数传递

时间:2019-11-15 10:08:38

标签: c++ qt smart-pointers unique-ptr qmetaobject

我正在Qt工作,我没有提到它,因为我认为这只是C ++问题。

我使用共享指针解决了这个问题,所以不要给我解决方案。但这是理解的问题,我想了解为什么它不起作用。

我正在尝试以下操作:

test.h:

#include <QObject>
#include "response.h"
#include <memory>

class Test : public QObject
{
    Q_OBJECT
public:
    explicit Test(QObject *parent = nullptr);

signals:
    void signal(std::unique_ptr<Response> resp);

public slots:

};

test.cpp:

Test::Test(QObject *parent) : QObject(parent)
{
    std::unique_ptr<Response> response(new Response(5));

    emit signal(std::move(response));
}

Response类:

class Response
{
public:
    Response(int data);

private:
     int data;
};

我知道无法复制std::unique_ptr,在这里使用std::move。但是尽管如此,我还是得到了一个错误:

moc_test.cpp:75:85: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Response; _Dp = std::default_delete<Response>]’
         case 0: _t->signal((*reinterpret_cast< std::unique_ptr<Response>(*)>(_a[1]))); break;

在Qt元对象系统的产品moc_test.cpp的以下代码段中:

void Test::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void `_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        auto *_t = static_cast<Test *>(_o);
        Q_UNUSED(_t)
        switch (_id) {
//------- !! This line!!
        case 0: _t->signal((*reinterpret_cast< std::unique_ptr<Response>(*)>(_a[1]))); break;
        default: ;
        }
    } else if (_c == QMetaObject::IndexOfMethod) {
        int *result = reinterpret_cast<int *>(_a[0]);
        {
            using _t = void (Test::*)(std::unique_ptr<Response> );
            if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Test::signal)) {
                *result = 0;
                return;
            }
        }
    }
}

花了很多时间,但我无法弄清楚为什么会发生该错误,并且在互联网上找不到任何帮助。

2 个答案:

答案 0 :(得分:2)

Qt信号传递取决于能否复制自变量。信号可以连接到许多插槽,因此传递唯一的指针没有任何意义。除了一个收件人以外的所有收件人都将为空。

您需要将其转换为共享指针或更改您的方法。

答案 1 :(得分:1)

link提到了对QT元类型施加的约束,即该类型需要一个复制构造函数(可发出)。

错误消息中提到 const 的原因是我怀疑unique_ptr的副本构造函数正在尝试被调用(如消息所指示)。

我怀疑当作为参数传递时正在发生移动时,您仍在分配右值(例如,在构造函数中)。

注意 ,您尚未发布所有代码,但我怀疑您的代码失败的原因与以下代码相同:

#include <memory>


struct Foo {
    std::unique_ptr<int> pointer_;

    explicit Foo(std::unique_ptr<int> pointer) : pointer_(pointer) {
    }
};

int main() {
    std::unique_ptr<int> pointer(new int(10));
    Foo{move(pointer)};


    // your code goes here
    return 0;
}

失败原因:

prog.cpp: In constructor ‘Foo::Foo(std::unique_ptr<int>)’:
prog.cpp:8:63: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
  explicit Foo(std::unique_ptr<int> pointer) : pointer_(pointer)

原因是正在进行复制初始化( pointer _ )。您需要调用move来将(现在是左值指针)移动到成员中。

我建议代码执行如下修改的初始化:

struct Foo {
  std::unique_ptr<int> pointer_;

  explicit Foo(std::unique_ptr<int>&& pointer) 
  : pointer_(move(pointer)) { //**NOTE** the move here!!!
  }
};

请注意,我没有按值传递std :: unique_ptr。实际上,它始终是RValue,并且可能会引发额外的move构造函数调用(我不确定,但是在这种情况下我只使用RValue引用)

相关问题