将std :: unique_ptr传递给成员函数,然后将其传递给QT线程连接内的lambda函数

时间:2017-08-08 14:11:45

标签: c++ multithreading qt lambda c++14

我一直在尝试对类似执行以下操作(提供以下内容是为了演示编译错误,所以如果你想编译它就可以了,仅此而已)

//main.cpp
#include <QApplication>
#include "test.h"

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    Test t;
    std::string s = "hi ";
    std::unique_ptr<std::string> sptr = std::make_unique<std::string>(s);
    t.foo(sptr);
    return a.exec();
}

test.h

//test.h
#ifndef TEST_H
#define TEST_H
#include <QObject>
#include <QThread>
#include <string>
#include <QApplication>
#include <memory>

class Test : public QObject{
    Q_OBJECT
public:
    void foo(std::unique_ptr<std::string> t_ptr);
    void bar(std::unique_ptr<std::string> t_ptr);
};


#endif //TEST_H

TEST.CPP

//test.cpp
#include "test.h"
#include <iostream>

void Test::foo(std::unique_ptr<std::string> t_ptr){
    QThread * thread = new QThread(this);
    moveToThread(thread);
    auto lambda = [=, uptr = std::move(t_ptr) ]()mutable{bar(uptr);};
    connect(thread, &QThread::started, lambda);
    connect(thread, &QThread::finished, thread, &QThread::deleteLater);
    thread->start();
}
void Test::bar(std::unique_ptr<std::string> t_ptr){
    t_ptr->append("hello");
    std::cout << *t_ptr << std::endl;
    moveToThread(QApplication::instance()->thread());
}

但无论我做什么,我似乎无法编译,我最终得到的只是:

 error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = std::__cxx11::basic_string<char>; _Dp = std::default_delete<std::__cxx11::basic_string<char> >]'
     auto lambda = [=, uptr = std::move(t_ptr) ]()mutable{bar(uptr);};
                                                                  ^
    note: declared here
       unique_ptr(const unique_ptr&) = delete;

或者除了那个错误之外,还有这个错误:

In member function 'void Test::foo(std::unique_ptr<T>)':
error: use of deleted function 'Test::foo(std::unique_ptr<std::__cxx11::basic_string<char> >)::<lambda()>::<lambda>(const Test::foo(std::unique_ptr<std::__cxx11::basic_string<char> >)::<lambda()>&)'
 connect(thread, &QThread::started, lambda);

更改为mutable也会导致相同的错误,显然我已经使用here找到了答案。

我确定这与lambda捕获使unique_ptr const成为事实有关,但后来我不知道该怎样做才能真正实现我想要实际做出的{{1一个成员变量。

编辑:

好吧,我在其他任何评论之前尝试过这些东西,而且它们也没有用,但因为我得到了关于“试试这个”的回复,我将向你展示其他一些不起作用的排列:

使用std :: move(uptr)(相同的错误)

unique_ptr

中的Lambda创建
connect

同样的错误。

更改connect(thread, &QThread::started, [=, uptr = std::move(sensor_ptr) ]()mutable{bar(uptr);};); 以获取右值,同样的错误

更改bar以获取const值,同样的错误

更改bar以获取const rvalue,同样的错误

3 个答案:

答案 0 :(得分:1)

错误消息告诉您无法复制 lambda

可以理解,因为你的lambda是一个以SELECT ProdName, ManuPartNo, Price, Qty, Supplier FROM (SELECT dbo.TableAllProds.*, ROW_NUMBER() OVER (PARTITION BY ManuPartNo ORDER BY Price ASC) AS RN FROM dbo.TableAllProds) AS t WHERE RN = 1 ORDER BY ManuPartNo 为成员的类 - 而且不可能默认复制这样的类。

std::unique_ptr<T>接受仿函数,可能会将其存储在内部某处。并且不可能复制你的lambda。

考虑例子:

QObject::connect

答案 1 :(得分:0)

您需要将uptr移动到栏中,并可能lambda进入连接。我也不知道 1 连接的目的地是否需要CopyConstructible / CopyAssignable,如果他们这样做,你无能为力。

1 - QT文档没有提及这些事情。

答案 2 :(得分:-1)

无法复制

std::unique_ptr<>,只能转发它们,否则它们持有的指针不会是唯一的。

如果您希望将指针的所有权转移给函数,则只能声明unique_ptr参数,如下所示:

void func(std::unique_ptr<foo>& bar);    // as a non-const reference
void func2(std::unique_ptr<foo>&& bar);  // using the move operator
void func3(std::unique_ptr<boo> bar);    // by value, call as func2(std::move(bar));

// call as

func(unique);
func2(unique);  // or the more expressive func2(std::move(unique)); 
func3(std::move(unique));

如果您不想转让所有权,最好将包含的对象作为裸指针或作为参考传递。

void func(foo* bar);  // could be const pointer

// call as 
func(unique.get());

// or...

void func(foo& bar);  // could be const reference

// call as 
func(*unique.get());

同样适用于将unique_ptr传递给lambda捕获。