vector of vector of unique_ptr

Jun 25, 2015 at 12:45pm
How do I fill a std::vector<std::vector<std::unique_ptr<Node>>> with blank vectors so that I can add to a specific level? I'm making a parse tree and I'm using a vector of unique_ptrs to manage ownership of each tier of nodes so I need a vector of vectors of unique_ptr and I can't do that because MinGW keeps coming up with errors such as no match for operator= in stl_vector.h.
Last edited on Jun 25, 2015 at 12:46pm
Jun 25, 2015 at 1:03pm
How do I fill a std::vector<std::vector<std::unique_ptr<Node>>> with blank vectors
std::vector<std::vector<std::unique_ptr<Node>>> stuff {size}; creates a vector containing size vectors
Jun 25, 2015 at 1:07pm
What if I don't know size at compile time?
Jun 25, 2015 at 1:10pm
std::vector<std::vector<std::unique_ptr<Node>>> stuff {size}; creates a vector containing size vectors in runtime. size can be a variable
Jun 25, 2015 at 1:14pm
Let me rephrase. This vector of vectors is inside a class but it will not be used until later and size is not known until long after the constructor of the class in which the vectors are situated.
Jun 25, 2015 at 1:18pm
Jun 25, 2015 at 1:22pm
Thank you. It works. (Or at least I think it does. It's part of a really big project and I'll have no idea if it works without logic errors for a while but it does compile).
Jun 25, 2015 at 1:29pm
creates a vector containing size

Does it?
We are talking about:
std::vector<Foo> bar { size };

If it would call the fill constructor,
explicit vector (size_type n, const allocator_type& alloc = allocator_type());,
then the bar would indeed contain size default-constructed Foo objects.
(I shadowmouse's case, using Foo = vector<unique_ptr<Node>>;, size empty vectors.)

However, the std::vector has an another constructor too:
vector (initializer_list<value_type> il, const allocator_type& alloc = allocator_type());

The question is, will the
1
2
3
4
5
6
7
8
9
std::vector<Foo> bar { size };

// be interpreted as

std::vector<Foo> bar ( size ); // call fill ctor

// or as

std::vector<Foo> bar ( initializer_list<Foo>(size) ); // call initlist ctor 

IIRC, the brace syntax deviously prefers the initlist.

No matter, the parentheses syntax is valid.
Jun 25, 2015 at 1:39pm
There is no way an integral number will be converted to initializer_list<vector<unique_ptr<foo>>> as vector constructor taking single parameter is explicit.
Jun 25, 2015 at 2:59pm
I'll have no idea if it works without logic errors for a while

This is what unit tests are for :)
Last edited on Jun 25, 2015 at 2:59pm
Jun 25, 2015 at 3:27pm
@MiiNiPaa: you are right, the explicit makes the difference. I had an inappropriate test case:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <vector>
#include <iostream>

struct Foo {
  Foo() = default;
  Foo( int ) {}
};

int main () {
 std::vector<Foo> foo ( 7 );
 std::vector<Foo> bar { 7 };
 std::vector<Foo> gaz ( 42, 7 );
 std::vector<Foo> qux { 42, 7 };
 std::cout << foo.size() << " vs " << bar.size() << " vs " << gaz.size()
   << " vs " << qux.size() << '\n';
 return 0;
}

7 vs 1 vs 42 vs 2



size is not known until long after the constructor

If the size is known right before adding elements, then the resize() or reserve()+emplace_back().
See http://www.cplusplus.com/reference/vector/vector/reserve/

If the size is known only after all the elements have been added, then plain emplace_back() -- unless you can make an educated guess for reserve().

The emplace_back() is usually more efficient than the older push_back(), but it depends on what objects you have to add.
Last edited on Jun 25, 2015 at 3:35pm
Topic archived. No new replies allowed.