vector of unique_ptrs - how to initialize?

Hi,

I have a vector of std::unique_ptr<Shape> but cannot initialize it.

I tried:

 
vector<std::unique_ptr<Shape>> v{ std::unique_ptr<Shape>(new Circle{12}) };


fpor types:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
	class Shape {		// Shape is polymorphic! 
		// vector<std::unique_ptr<Shape>> v { new Circle{},new Shape{}};
		// v[0]->draw(); v[1]->draw(); …; auto p = v[0]->clone();
		int x;
		int y;
	public:
		Shape() = default;
		Shape(const Shape&) = delete; // no copy operations – slicing would occur
		Shape& operator=(const Shape&) = delete; // no assignment ops – slicing would occur
		Shape(Shape&&) = delete; // no move operations – slicing would occur
		Shape& operator=(Shape&&) = delete;  // no move assignments – slicing would occur
		virtual ~Shape() = default;
		virtual void draw() {}
		virtual Shape* clone() { return nullptr; }
		// ...
	};

	class Circle : public Shape
	{
		int radius;
	public:
		Circle(int rad) : radius(rad) {}
		void draw() override {}
		Shape* clone() override { return new Circle{ radius };}
		~Circle() override = default;
	};



I get Error


attempting to reference a deleted function


All I have been able to do is


 
v.emplace_back(new Circle{23});


I also tried with no success:

1
2
std::unique_ptr<Shape> circ{new Circle{12}};
v.push_back(std::move(circ));


The std::vector constructor that you're trying to call uses std::initializer_list but std::initializer_list unfortunately doesn't allow "perfect forwarding" (it's only possible to copy from it) so that is why it doesn't work with move-only types like std::unique_ptr.
Last edited on
but how to initialize the vector of unique_ptrs?
did you try make_unique?
However what you are attempting may not be doable. Unique ptr prevents a great many things that should work, because that is its special magic thing that makes it useful (the same limitations that make it *unique* are behind it, preventing copies mostly).
Last edited on
The code you wrote earlier should work.

1
2
std::unique_ptr<Shape> circ{new Circle{12}};
v.push_back(std::move(circ));


Using std::make_unique is also a good idea.

1
2
auto circ = std::make_unique<Circle>(12);
v.push_back(std::move(circ));


Note that you can pass the unique_ptr to push_back directly without storing it in a variable first. Then you don't even need to use std::move.

 
v.push_back(std::make_unique<Circle>(12));
Last edited on
1
2
std::vector<std::unique_ptr<Shape>> v;
v.push_back(std::make_unique<Circle>(12));


As Peter87 says above, that is OK.

But this:

 
std::vector<std::unique_ptr<Shape>> v {std::make_unique<Circle>(12)};


is a no-no as Peter87 says in his earlier post. You can't use a move-only type (like std::unique_ptr) with std::initializer_list

You'll need to initialise the vector by individually pushing each required element onto the vector.
Last edited on
I understand, but the why is not clear to me. Peter87 says something about perfect forwarding and initializer_list, can you expand on that? Why does initializer_list not suppport perfect forwarding? why this limitation? can it be added to a subclass?


Last edited on
std::initializer_list only gives const access to the elements. You cannot move the elements of a std::initializer_list. You're forced to copy them.

Apparently std::initializer_list was designed before move semantics.

std::initializer_list was designed around 2005 to 2007, before move semantics matured, around 2009. At the time, it was not anticipated that copy semantics would be insufficient or even suboptimal for common value-like classes.
From: https://open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4166.pdf
Topic archived. No new replies allowed.