使用 std::move 将 std::unique_ptr 作为 qt 信号参数传递
Passing std::unique_ptr as qt signal argument with std::move
我在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:
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;
在以下 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;
}
}
}
}
花了很多时间,但我无法弄清楚为什么会出现该错误,也没有在互联网上找到任何有用的信息。
Creating Custom Qt Types 提到了对 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
将(现在是左值 pointer
)移动到成员中。
我建议代码执行初始化修改如下:
struct Foo {
std::unique_ptr<int> pointer_;
explicit Foo(std::unique_ptr<int>&& pointer)
: pointer_(move(pointer)) { //**NOTE** the move here!!!
}
};
请注意,我没有按值传递 std::unique_ptr
。在实践中,它总是一个右值,并且可能会省略额外的移动构造函数调用(我不确定,但我只是在这些情况下使用右值引用)。
另请注意,无需限定 move
,因为它将作为 ADL.
的结果进行查找
Qt 信号传递取决于能否复制参数。一个信号可以连接到很多槽,所以传递一个唯一的指针没有意义;除了一个收件人之外,所有收件人都会得到一个空值。
您需要将其转换为共享指针或改变您的方法。
我在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:
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;
在以下 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;
}
}
}
}
花了很多时间,但我无法弄清楚为什么会出现该错误,也没有在互联网上找到任何有用的信息。
Creating Custom Qt Types 提到了对 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
将(现在是左值 pointer
)移动到成员中。
我建议代码执行初始化修改如下:
struct Foo {
std::unique_ptr<int> pointer_;
explicit Foo(std::unique_ptr<int>&& pointer)
: pointer_(move(pointer)) { //**NOTE** the move here!!!
}
};
请注意,我没有按值传递 std::unique_ptr
。在实践中,它总是一个右值,并且可能会省略额外的移动构造函数调用(我不确定,但我只是在这些情况下使用右值引用)。
另请注意,无需限定 move
,因为它将作为 ADL.
Qt 信号传递取决于能否复制参数。一个信号可以连接到很多槽,所以传递一个唯一的指针没有意义;除了一个收件人之外,所有收件人都会得到一个空值。
您需要将其转换为共享指针或改变您的方法。