2

I'm trying to use the "fill" version of the std::vector constructor. It takes the number of elements as the first argument, and const value_type& as the second argument:

#include <vector>

int main()
{
    std::vector<int> v(100, 7);
    // Works, creates vector with 100 elements of int 7.

}

However I can't seem to make this work with unique_ptrs:

#include <vector>
#include <memory>

int main()
{
    std::vector<std::unique_ptr<int>> v1(100, std::unique_ptr<int>());
    std::vector<std::unique_ptr<int>> v2(100, std::make_unique<int>());

}

Both don't work with unique_ptrs. The error I get from Visual Studio 2017 is:

Error C2280 'std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function

Considering the second argument takes const reference to the type contained in the vector, I expected std::unique_ptr() or std::make_unique() to simply work as the second argument. I know they're both temporaries, but seeing as the argument is const reference, it should accept it, why way it accepted it accepted integer 7 for the argument in my first example that works.

Also, std::unique_ptr() looks very close to "most vexing parse" however the examples at cppreference.com use it:

// Use the default constructor.
    std::unique_ptr<Vec3> v1 = std::make_unique<Vec3>();

As I said, this looks something like "most vexing parse", being a function signature for a function taking no arguments and returns a std::unique_ptr< Vec3 >

Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • 2
    This constructor would have to make n **copies** of a move-only type... – Marc Glisse Aug 04 '18 at 20:14
  • 3
    Lose the second argument. Just use `var(count)`. Instances will be default-constructed. Your alternative is to use something like `std::generate_n` with a lambda or callback that generates a unique, movable object with each item added (and that would ultimately be pointless if all you want is a raft of unique pointer objects pointing to nothing; the first option is better). – WhozCraig Aug 04 '18 at 20:14
  • 1
    You attempt to create a vector of `100` ***copies*** of a unique pointer object. And there's the problem: `std::unique_ptr` *can't be copied*. – Some programmer dude Aug 04 '18 at 20:14
  • @Some programmer dude, I knew they couldn't be copied, but I thought they would moved instead. – Zebrafish Aug 04 '18 at 20:41
  • @Zebrafish think about it. You are trying to *fill* the vector, which means each element would have the same value. How would you expect a single input value to fill 100 elements with the same value without making copies? Moving an object doesn't make more copies of it. – Remy Lebeau Aug 05 '18 at 00:25
  • @Remy Lebeau, Yeah thanks, that makes perfect sense. – Zebrafish Aug 05 '18 at 00:45
  • There is no `=` in a function signature – M.M Aug 05 '18 at 00:54
  • @M.M Ah yes, I keep on getting mixed up. No I thought what was after the equals sign was a function signature, but there's no ambiguity I'm pretty sure. Foo b(); is problematic, Foo b = Foo(); isn't. Thanks. – Zebrafish Aug 05 '18 at 02:27

1 Answers1

5

The std::vector constructor you are attempting to use has to copy the input value provided in order to populate the vector to the requested size. Not being able to copy a std::unique_ptr is one of its most important features, so you shouldn’t be surprised that your code does not work.

If you drop the second argument, each value in the vector will be constructed with std::unique_ptr's default constructor; thus making no copies. This is what you are trying to do anyway.

See also: How to initialize a vector of unique_ptr with null pointers?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
idmean
  • 14,540
  • 9
  • 54
  • 83
  • I thought a vector could hold elements which couldn't be copied, but moved. Foo still has a move constructor/assignment operator, which is why I thought it would work. – Zebrafish Aug 04 '18 at 20:40
  • In attempting to copy the object and finds there's no copy assignment operator or copy constructor, doesn't it then use the move assignment operator or move constructor? – Zebrafish Aug 04 '18 at 20:59
  • 1
    But moving does not help in creating n (the number you provided) values. If you have a vector of n values you need to construct exactly n values. The constructor you tried to use tries to achieve this by making copies of the value you provided. Moving does not help as you can move a value as often as you want — it’s still just one. – idmean Aug 04 '18 at 21:24