-3

I've been trying to do something similar to the following (the following is provided to demonstrate the compilation error so if you wanted to compile it you could, nothing more)

//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());
}

But I can't seem to compile no matter what I do, I end up with either just this:

 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;

or in addition to that error, this one as well:

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

Changing to mutable results in the same error as well, and obviously I've already imployed the answer found here.

I'm sure it has to do with the fact that the lambda capture makes the unique_ptr const, but then i'm not sure what to do to actually accomplish what I want sans actually making the unique_ptr a member variable.

EDIT:

Ok, I tried these things before any one else commented, and they also didn't work, but because I'm getting responses about "try this" I'm going to show you some other permutations that don't work:

Using std::move(uptr) (same error)

Lambda creation in connect

connect(thread, &QThread::started, [=, uptr = std::move(sensor_ptr) ]()mutable{bar(uptr);};);

same error.

Changing bar to take rvalue, same error

Changing bar to take const value, same error

Changing bar to take const rvalue, same error

Krupip
  • 4,404
  • 2
  • 32
  • 54
  • `bar(std::move(uptr));` within the lambda. If you still see an error, please post a [mcve]. You might also need `std::move(lambda);` here - `connect(thread, &QThread::started, lambda);`, but I'm not sure how `connect` works. – Praetorian Aug 08 '17 at 14:15
  • @Praetorian The qt stuff isn't relevant? How so? also this is pretty minimal... – Krupip Aug 08 '17 at 14:16
  • @Praetorian, I also used std::move doesn't fix anything, it still thinks I'm using const unique_ptr constructor which is deleted... – Krupip Aug 08 '17 at 14:18
  • The example is incomplete and cannot be compiled by anyone else. The Qt stuff might be relevant, but the first step is to take it out and see if you can still reproduce the problem. If you can't then add it back in one thing at a time. – Praetorian Aug 08 '17 at 14:19
  • @Praetorian Ok updated with verifiable example, same error. – Krupip Aug 08 '17 at 14:39
  • `std::make_unique(&s)` ?! – Jarod42 Aug 08 '17 at 19:07
  • @jarod42 won't work, additionally I've already implemented a simpler solution which takes the pointer out of the unique_ptr uses it (but doesn't delete it or anything). This post about how to not find away around it or explaining why it is impossible in detail. – Krupip Aug 08 '17 at 19:15
  • I meant that it is a invalid syntax (missing ``), it should not take reference of existing pointer. In addition `std::unique_ptr` is suspicious, why not use `std::string` directly ? – Jarod42 Aug 08 '17 at 19:23
  • @Jarod42 Are you serious right now? Tell me you are not serious. That is a minimal verifiable example, it has *absolutely zero* to do with what I'm actually doing (the actual type I'm using is *not* a string) I'm merely demonstrating the problem here. Additionally where are you even seeing "missing " that is certainly not an error I've gotten, and I'm not taking a reference to an existing pointer any where here. – Krupip Aug 08 '17 at 19:46
  • Yes, I'm serious. You have so many mistakes in main function (`std::make_unique(s)`, `t.foo(std::move(sptr));`), memory leak in the problematic function. The example is not minimal (you could move all code in main.pp). That has probably nothing to do with your problem, but all those extra error doesn't help us to help you. – Jarod42 Aug 08 '17 at 20:05
  • @Jarod42 In my compiler, the errors that I specified came up first before anything else, hence why i didn't catch the string issue. I also don't see a memory leak. Can you honestly say you aren't being pedantic when you say "its not all in one file". Would that not be the same amount of space (in addition to potential errors that can arise from doing so )? You also weren't being clear *at all* on specific issues, you didn't even mention anything you were talking about from your last post this time – Krupip Aug 08 '17 at 20:41
  • @Jarod42 Ah, I forgot to set the parent. The convention in QT is to use pointers for everything because children will be deleted when the parent is (in my real code the parent is something else). – Krupip Aug 08 '17 at 20:59
  • @Jarod42 Actually my bad, delete later will actually destroy the thread, there was never a memory leak – Krupip Aug 09 '17 at 13:20

3 Answers3

1

Error message tells that it's not possible to copy lambda.

And it can be understood, because your lambda is a class with std::unique_ptr<T> as member - and it's not possible to default-copy such class.

QObject::connect accepts functor and, probably, stores it somewhere internally. And it's not possible to make a copy of your lambda.

Consider example:

template<typename T>
void UseFunctor(T i_functor)
{
    T functor_backup = i_functor; // fails to compile because of copying lambda
    // ...
    functor_backup();
}

int main() 
{
    std::unique_ptr<int> p_int = std::make_unique<int>(10);
    UseFunctor([p_ptr = std::move(p_int)](){});
}
k.v.
  • 1,193
  • 8
  • 11
0

You need to move uptr into bar, and probably lambda into connect. I also don't know1 whether the destination of connect needs to be CopyConstructible / CopyAssignable, if they do there's nothing you can do about it.

1 - The QT documentation is silent on such things.

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • originally I had the entire lambda in connect, it did the same thing, I can't show every permutation I've tried unfortunately. – Krupip Aug 08 '17 at 14:21
  • I think you just have to replace `unique_ptr` with `shared_ptr` to use it with QThread::started. Alternatively you could use `std::thread`, which does perfect forwarding in it's constructor – Caleth Aug 08 '17 at 14:25
  • Unfortunately I don't believe I can use std::thread with out significant changes, as I need to move my QObject over there (qt has some odd thread syntax) – Krupip Aug 08 '17 at 14:55
-1

std::unique_ptr<> cannot be copied, they can only be forwarded, otherwise the pointers they hold wouldn't be unique.

If you wish to transfer ownwership of the pointer to a function, you can only declare the unique_ptr parameter as follows:

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

If you do not wish to transfer ownership, it's best to pass the contained object as a naked pointer, or as a reference.

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());

The same holds for passing unique_ptr's to lambda captures.

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19