简体   繁体   中英

using std::move to move a unique_ptr into a vector

I have been trying to create a unique_ptr , and then move it into a vector of that pointer with push_back() . When I try to do this, I get a long compilation error. I have read multiple questions on this subject, including the section on "Containers of unique_ptr" here: https://eli.thegreenplace.net/2012/06/20/c11-using-unique_ptr-with-standard-library-containers

As well as this StackOverflow question: Why can I not push_back a unique_ptr into a vector?

This is a tiny sample program that will not compile:

// ptrtest.cpp
#include <memory>
#include <vector>

class TestObject{
public:
    TestObject(int data): data(data){}
    int getData(){return data;}
private:
    int data;
};

using namespace std;
int main (int argc, char* argv[]){
    vector<unique_ptr<TestObject> > v;
    unique_ptr<TestObject> obj = unique_ptr<TestObject>(new TestObject(5));
    v.push_back(move(obj));

    return 0;
}

This is the compiler error the program gives me:

$ clang++ ptrtest.cpp -otest
In file included from ptrtest.cpp:1:
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1574:36: error: 
      no matching constructor for initialization of
      'std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> >'
                ::new ((void*)__p) _Tp(__a0);
                                   ^   ~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/vector:1593:25: note: in
      instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > >
      >::construct<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >, std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > >' requested here
        __alloc_traits::construct(this->__alloc(),
                        ^
ptrtest.cpp:16:4: note: in instantiation of member function
      'std::__1::vector<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >,
      std::__1::allocator<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > > >::push_back' requested here
        v.push_back(move(obj));
          ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:2482:3: note: 
      candidate constructor not viable: 1st argument ('const
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> >')
      would lose const qualifier
  unique_ptr(unique_ptr&);
  ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:2498:3: note: 
      candidate constructor not viable: no known conversion from 'const
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> >'
      to 'std::__1::nullptr_t' for 1st argument
  unique_ptr(nullptr_t) : __ptr_(pointer())
  ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:2504:12: note: 
      candidate constructor not viable: no known conversion from 'const
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> >'
      to 'std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject>
      >::pointer' (aka 'TestObject *') for 1st argument
  explicit unique_ptr(pointer __p)
           ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:2516:3: note: 
      candidate constructor not viable: no known conversion from 'const
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> >'
      to '__rv<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > >' for 1st argument
  unique_ptr(__rv<unique_ptr> __u)
  ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:2483:35: note: 
      candidate template ignored: deduced type 'unique_ptr<...>' of 1st
      parameter does not match adjusted type 'const unique_ptr<...>' of
      argument [with _Up = TestObject, _Ep =
      std::__1::default_delete<TestObject>]
  template <class _Up, class _Ep> unique_ptr(unique_ptr<_Up, _Ep>&);
                                  ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:2490:3: note: 
      candidate constructor not viable: requires 0 arguments, but 1 was provided
  unique_ptr() : __ptr_(pointer())
  ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:2535:3: note: 
      candidate constructor not viable: requires 2 arguments, but 1 was provided
  unique_ptr(pointer __p, deleter_type __d)
  ^
In file included from ptrtest.cpp:2:
/Library/Developer/CommandLineTools/usr/include/c++/v1/vector:1580:21: error: 
      no matching member function for call to 'construct'
    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_), ...
    ~~~~~~~~~~~~~~~~^~~~~~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/vector:1599:9: note: in
      instantiation of function template specialization
      'std::__1::vector<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >,
      std::__1::allocator<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > > >::__push_back_slow_path<const
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> > >'
      requested here
        __push_back_slow_path(__x);
        ^
ptrtest.cpp:16:4: note: in instantiation of member function
      'std::__1::vector<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >,
      std::__1::allocator<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > > >::push_back' requested here
        v.push_back(move(obj));
          ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1572:21: note: 
      candidate template ignored: substitution failure [with _Tp =
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> >,
      _A0 = std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >]
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0)
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1566:21: note: 
      candidate function template not viable: requires 2 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p)
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1578:21: note: 
      candidate function template not viable: requires 4 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0,
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1585:21: note: 
      candidate function template not viable: requires 5 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0,
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1677:17: error: 
      use of undeclared identifier 'construct'
                construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD:...
                ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/vector:898:21: note: in
      instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > >
      >::__construct_backward<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > *>' requested here
    __alloc_traits::__construct_backward(this->__alloc(), this->__begin_...
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/vector:1582:5: note: in
      instantiation of member function
      'std::__1::vector<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >,
      std::__1::allocator<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > > >::__swap_out_circular_buffer'
      requested here
    __swap_out_circular_buffer(__v);
    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/vector:1599:9: note: in
      instantiation of function template specialization
      'std::__1::vector<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >,
      std::__1::allocator<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > > >::__push_back_slow_path<const
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> > >'
      requested here
        __push_back_slow_path(__x);
        ^
ptrtest.cpp:16:4: note: in instantiation of member function
      'std::__1::vector<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >,
      std::__1::allocator<std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> > > >::push_back' requested here
        v.push_back(move(obj));
          ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1566:21: note: 
      must qualify identifier to find this declaration in dependent base class
        static void construct(allocator_type&, _Tp* __p)
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1572:21: note: 
      must qualify identifier to find this declaration in dependent base class
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0)
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1578:21: note: 
      must qualify identifier to find this declaration in dependent base class
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0,
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1585:21: note: 
      must qualify identifier to find this declaration in dependent base class
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0,
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1677:17: error: 
      no matching function for call to 'construct'
                construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD:...
                ^~~~~~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1572:21: note: 
      candidate template ignored: substitution failure [with _Tp =
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> >,
      _A0 = std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >]
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0)
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1566:21: note: 
      candidate function template not viable: requires 2 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p)
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1578:21: note: 
      candidate function template not viable: requires 4 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0,
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1585:21: note: 
      candidate function template not viable: requires 5 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0,
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1677:17: error: 
      no matching function for call to 'construct'
                construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD:...
                ^~~~~~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1572:21: note: 
      candidate template ignored: substitution failure [with _Tp =
      std::__1::unique_ptr<TestObject, std::__1::default_delete<TestObject> >,
      _A0 = std::__1::unique_ptr<TestObject,
      std::__1::default_delete<TestObject> >]
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0)
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1578:21: note: 
      candidate function template not viable: requires 4 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0,
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1585:21: note: 
      candidate function template not viable: requires 5 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p, const _A0& __a0,
                    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1566:21: note: 
      candidate function template not viable: requires 2 arguments, but 3 were
      provided
        static void construct(allocator_type&, _Tp* __p)
                    ^
5 errors generated.

My compiler is clang++ and I'm running macOS 10.14.3.

Are you sure you are using c++11?

Prior to c++11 the signature for push_back(...) was:

void push_back (const value_type& val);

So even if you give a temporary it will still use the copy constructor.

In C++11 there is an overload to handle the use of temporary variables to move instead of copy.

Either way, you should consider using .emplace_back(...). This was specifically made for handling temporaries and inline constructing the object so there is no copy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM