簡體   English   中英

使用 std::move 將 std::unique_ptr 作為 qt 信號參數傳遞

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

我在Qt工作,我沒有提到它,因為我認為這只是C++問題。

我用共享指針解決了這個問題,所以不要給我解決方案。 但這是理解的問題,我想了解為什么它不起作用。

我正在嘗試以下操作:

測試.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:

};

測試.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;
            }
        }
    }
}

花了很多時間,但我無法弄清楚為什么會發生這個錯誤,並且在互聯網上沒有找到任何有用的東西。

Qt 信號傳輸取決於能否復制 arguments。 一個信號可以連接很多槽,所以傳遞一個唯一的指針是沒有意義的; 除一位收件人外,其他所有人都將獲得 null。

您需要將其轉換為共享指針或更改您的方法。

創建自定義 Qt 類型提到了對 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的結果進行查找。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM