1

I am trying to pass a unique_ptr into a custom vector class but I am receiving the error in the subject title.

I understand that you cannot copy a unique_ptr and so I am trying to use std::move() when passing it, however that doesn't seem to solve my problem... Where am I going wrong?

Thanks in advance

template<typename T>
class VectorSelectable {
public:
    void Add(const T& v) { 
        m_Items.push_back(move(v)); 
    }
private:
    vector<T> m_Items;
};

class FunctionType {
    int m_Data;
};

int main()
{
    VectorSelectable<unique_ptr<FunctionType>> vec;
    vec.Add(move(make_unique<FunctionType>()));
    return 0;
}

Edit: Added 'const' to 'Add(const T& v)'

  • You know the rvalue reference you get from `std::move` has decayed back to an lvalue reference in the `Add` method, because you wrote the argument list `T& v`. If you want it to take `T&& v` you have to write that. – Useless Dec 01 '21 at 10:43
  • Moving `const` object leads to copy in most cases... – Jarod42 Dec 01 '21 at 11:49

3 Answers3

2

If you want to allow both copy-via-const-ref and move-via-rvalue-ref, you can either template your Add method and use the universal forwarding reference technique, or write two overloads explicitly:

    void Add(const T& v) { 
        m_Items.push_back(v); 
    }
    void Add(T&& v) { 
        m_Items.push_back(std::move(v)); 
    }

or

    template <typename U>
    void Add(U&& v) { 
        m_Items.push_back(std::forward<U>(v)); 
    }
Useless
  • 64,155
  • 6
  • 88
  • 132
  • Thanks, 2 overloads is the perfect solution :) – Max Peglar-Willis Dec 01 '21 at 10:57
  • Yes, it's up to the caller to select the correct overload here, and it works with the code given. We could use SFINAE to disable the copy overload entirely, but it's not required for the question as asked. – Useless Dec 01 '21 at 11:02
1

The Add() accepts an lvalue reference of T, but move(make_unique<FunctionType>()) returns an rvalue reference, you cannot bind an rvalue to an lvalue reference.

You can turn Add() into a template function and use forwarding references to accept lvalues and rvalues and move them into your m_Items.

template<class U>
void Add(U&& v) { 
    m_Items.push_back(move(v)); 
}

Demo.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
-1

@Max Peglar-Willis The problem here is that somewhere, your code is attempting to call the "copy-assignment" operator.

This causes the compiler to attempt to generate a copy-assignment operator which calls the copy-assignment operators of all the subobjects. Eventually, this leads to an attempt to copy a unique_ptr,

an operation that is not possible.

Smit Gajera
  • 1,001
  • 1
  • 8
  • 26