Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot emplace_back() a braced initializer on a vector of vectors

Tags:

This is somewhat related to a previous question I asked regarding using emplace_back on a vector of pairs. emplace_back() vs push_back when inserting a pair into std::vector

Now my question pertains to using emplace_back on a vector of vectors.

Here is the code that I am questioning about with comments

std::vector<std::vector<int>> matrix;

matrix.emplace_back({1,2,3}); //doesn't compile

matrix.emplace_back(1,2,3); //doesn't compile

matrix.push_back({1,2,3}); //works and does what is expected (insert a vector made of {1,2,3} into matrix);

matrix.emplace_back(std::vector<int>{1,2,3});   //works but 
//defeats the purpose of using emplace_back since this makes a copy
//and is thus equivalent to push_back in this case?

matrix.emplace_back(3,2) //this compiles, 
//but it seems to insert a vector of size 3 made of 2s into the matrix. 
//not actually sure why it does this

So, from this, matrix.emplace_back(std::vector<int>{1,2,3}); seems to be the only correct way to use std::vector<T>::emplace_back on a vector of vectors, but this seems to offer no advantages over push_back. Is my understanding on this matter correct?

Also, could someone explain why matrix.emplace_back(3,2) is inserting a vector of size 3 made of 2s into the matrix?

like image 890
24n8 Avatar asked Jun 06 '19 19:06

24n8


1 Answers

The {1, 2, 3} cannot be deduced to initializer_list<int> in this case (which is what the vector<int> constructor you want to use expects.) So you need to help it along a bit:

matrix.emplace_back(initializer_list<int>{1, 2, 3});

This is not required when using push_back(). I don't know the exact details, but emplace_back() is a function template while push_back() is not. Deduction rules for templates are different (way more strict.) And a braced initializer has no type. Because of that, it comes with its own special rules on how type deduction works.

As for efficiently, this:

matrix.emplace_back(vector<int>{1, 2, 3});

constructs two vectors. An empty vector in matrix, and the passed temporary. The temporary is moved into the empty vector. So it's not that bad really.

However, this:

matrix.emplace_back(initializer_list<int>{1, 2, 3});

Only constructs one vector, using the constructor that accepts an initializer_list. Note that there's no "extra" initializer_list object being created here. Such an object is going to be created anyway when creating any vector using braced initialization:

vector<int> vec{1, 2, 3};

This also creates an initializer_list object, because that's what the vector constructor takes.

As for why emplace_back(2,3) works, that's because there's a vector constructor that takes a size and a value.

like image 58
Nikos C. Avatar answered Nov 03 '22 01:11

Nikos C.