简体   繁体   English

使用 std::move 将 std::unique_ptr 作为 qt 信号参数传递

[英]Passing std::unique_ptr as qt signal argument with std::move

I'm working in Qt, I didn't mention it, because I thought it was just C++ problem.我在Qt工作,我没有提到它,因为我认为这只是C++问题。

I solved this problem with shared pointers, so don't give me solution.我用共享指针解决了这个问题,所以不要给我解决方案。 But it's question of comprehending, I want to understand why it's not working.但这是理解的问题,我想了解为什么它不起作用。

I was trying the following:我正在尝试以下操作:

test.h:测试.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:测试.cpp:

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

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

Response class: Response class:

class Response
{
public:
    Response(int data);

private:
     int data;
};

I know that std::unique_ptr can't be copied and I use std::move here.我知道std::unique_ptr不能被复制,我在这里使用std::move But in spite of this I get an error:但尽管如此,我得到一个错误:

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;

In the following snippet of moc_test.cpp , which is product of Qt meta-object system:moc_test.cpp的以下片段中,它是 Qt 元对象系统的产品:

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;
            }
        }
    }
}

Spent much time, but I couldn't figure it out why that error occurred and didn't find anything helpful in the internet.花了很多时间,但我无法弄清楚为什么会发生这个错误,并且在互联网上没有找到任何有用的东西。

Qt signal delivery depends on being able to copy the arguments. Qt 信号传输取决于能否复制 arguments。 A signal can be connected to many slots, so it doesn't make sense to pass a unique pointer;一个信号可以连接很多槽,所以传递一个唯一的指针是没有意义的; all but one of the recipients would get a null.除一位收件人外,其他所有人都将获得 null。

You'll need to convert it to shared pointer or change your approach.您需要将其转换为共享指针或更改您的方法。

Creating Custom Qt Types mentions the constraints imposed on a Qt meta-type, ie the type requires a copy constructor (to be emit-able).创建自定义 Qt 类型提到了对 Qt 元类型施加的约束,即该类型需要一个复制构造函数(可以发出)。

The reason that const is mentioned in the error message is that we're trying to invoke the (deleted) copy constructor of the unique_ptr (as indicated by the message).错误消息中提到const的原因是我们试图调用unique_ptr的(已删除)复制构造函数(如消息所示)。

I suspect that while the move is taking place when passed as parameter, you're still assigning the rvalue (eg in the constructor).我怀疑当作为参数传递时发生移动时,您仍在分配右值(例如在构造函数中)。

Note , you haven't posted all the code, but my suspicion is that your code fails for the same reason as the code below:请注意,您尚未发布所有代码,但我怀疑您的代码失败的原因与以下代码相同:

#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;
}

The failure being:失败是:

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)

The reason is that copy initialization is taking place (of pointer_ ).原因是正在发生复制初始化( pointer_ _)。 You need to call move to move the (now lvalue pointer ) into the member.您需要调用move将(现在的左值pointer )移动到成员中。

I would suggest the code perform the initialization to be modified as follows:我建议代码执行初始化修改如下:

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

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

Note that I did not pass std::unique_ptr by value.请注意,我没有按值传递std::unique_ptr In practice it would always be an rvalue, and perhaps the additional move constructor call would be elided (I'm not sure, but I just use an rvalue reference in these circumstances).在实践中它总是一个右值,并且可能会省略额外的移动构造函数调用(我不确定,但我只是在这些情况下使用右值引用)。

Also note that it is not necessary to qualify move , as it will looked up as result of ADL .另请注意,没有必要限定move ,因为它将作为ADL的结果进行查找。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM