Why How to Not Push_Back a Unique_Ptr into a Vector

Why can I not push_back a unique_ptr into a vector?

You need to move the unique_ptr:

vec.push_back(std::move(ptr2x));

unique_ptr guarantees that a single unique_ptr container has ownership of the held pointer. This means that you can't make copies of a unique_ptr (because then two unique_ptrs would have ownership), so you can only move it.

Note, however, that your current use of unique_ptr is incorrect. You cannot use it to manage a pointer to a local variable. The lifetime of a local variable is managed automatically: local variables are destroyed when the block ends (e.g., when the function returns, in this case). You need to dynamically allocate the object:

std::unique_ptr<int> ptr(new int(1));

In C++14 we have an even better way to do so:

make_unique<int>(5);

What is the correct usage of std::unique_ptr while pushing into std::vector

Consider the vec.push_back(). It has two overloads which take either const std::unique_ptr<int>& or std::unique_ptr<int>&&. The first overload can never be used. This is because the vector<> requires the type to be assignable, or movable (C++11 addition). 'Assignability' implies copying. push_back(const T&) will try to copy (assign) the incoming value to the new space at the end of the container. std::unique_ptr<> represents a resource that is owned by a single owner. By copying it (the pointer) multiple owners would be present. Because of that unique_ptr is not copyable.

Having said all of it, you can only use the T&& overload.

createPtr() returns std::unique_ptr<int>, but as this is a temporary result (function return value) it is considered a rvalue reference (implicitly). That is why this can be used.

ptr is just a std::unique_ptr<int> which is a lvalue reference (no matter if you put && next to it, as named rvalues are still treated as lvalues). Lvalue is never implicitly converted to rvalue (completely unsafe). But you can basically tell the compiler "Ok, you can take the object I pass you, and I promise I won't expect the argument to be left intact" by using std::move().

error with vector, unique_ptr, and push_back

push_back expects an std::unique_ptr, when passing raw pointer like new Square, which is considered as copy-initialization, the raw pointer needs to be converted to std::unique_ptr implicitly. The implicit conversion fails because std::unique_ptr's conversion constructor from raw pointer is marked as explicit.

emplace_back works because it forwards arguments to the constructor of std::unique_ptr and construct element in direct-initialization form, which considers explicit conversion constructors.

The arguments args... are forwarded to the constructor as std::forward<Args>(args)....

Why does push_back fail for unique_ptr of string vectors?

You have declared a std::unique_ptr using its default constructor, so it is holding a nullptr pointer. You are not creating a std::vector object for it to point at.

Use new to create the std::vector:

int main() {
auto vect = std::unique<std::vector<std::string>>(new std::vector<std::string>);
// or:
// std::unique<std::vector<std::string>> vect(new std::vector<std::string>);
vect->push_back("abc");
vect->emplace_back("abc");
return 0;
}

Or, in C++14 and later, use std::make_unique() instead of constructing the std::vector manually:

int main() {
auto vect = std::make_unique<std::vector<std::string>>();
vect->push_back("abc");
vect->emplace_back("abc");
return 0;
}

However you really should not create standard containers in dynamic memory, unless you absolutely need to.

int main() {
std::vector<std::string>> vect;
vect.push_back("abc");
vect.emplace_back("abc");
return 0;
}

How to push_back a unique_ptrBase& to vectorunique_ptrDerived

You can iterate on fromBase list and make your checks, if that requirement is met then you can simply release the pointer - which gives away the base pointer without calling destructor on it. Just make sure to remove such empty pointers that were released, in case you need to use fromBase vector again.

WANDBOX LINK

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>

using namespace std;

class Base{ public: virtual ~Base() = default; };
class Derived: public Base {};


int main() {
vector<unique_ptr<Base>> fromBase;
vector<unique_ptr<Derived>> toDerived;

fromBase.emplace_back(make_unique<Base>());
fromBase.emplace_back(make_unique<Base>());
fromBase.emplace_back(make_unique<Derived>());

for(auto& p: fromBase) {
Derived* d = dynamic_cast<Derived *>(p.get());
// make other checks here
if(d != nullptr) {
toDerived.emplace_back(d);
p.release();
}
}

// make sure to remove released pointers
fromBase.erase(remove_if(fromBase.begin(), fromBase.end(), [](const auto& p) { return !p; }), fromBase.end());

cout << fromBase.size() << " " << toDerived.size() << endl;
}

Pushing an object with unique_ptr into vector in C++

State is not copyable, but only moveable; But for states.push_back(nstate);, nstate is an lvalue (as a named variable), which can't be moved from. Then a copy is tried to perform but it's not allowed.

To solve it you could use std::move (to turn it to an rvalue):

states.push_back(std::move(nstate));

LIVE


Note that after the move operation, the data member of nstate (including the vector and its content) will be moved too.

Can't push_back an unique_ptr in a vector

When using unique_ptr you need to explicitly define the class T where-ever you declare the unique_ptr<T>. I.e. include the header for the class GameState, do not forward declare in the header game.h.

This will get rid of error: invalid application of 'sizeof' to incomplete type 'GameState'.

You can find more detailed answer here.



Related Topics



Leave a reply



Submit