Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a container of unique_ptr to constructor?

What am I missing here? Why can't I move a vector as part of class constructor? Removing const from the constructor doesn't help either.

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

using namespace std;

class Bar
{
public:
  Bar(const vector<unique_ptr<char>> vec);
  vector<unique_ptr<char>> vec_;
};

Bar::Bar(const vector<unique_ptr<char>> vec) :
  vec_(move(vec)) //not ok
{
}

int main()
{
  vector<unique_ptr<char>> vec;
  vec.push_back(unique_ptr<char>(new char('a')));
  vec.push_back(unique_ptr<char>(new char('b')));
  vec.push_back(unique_ptr<char>(new char('c')));
  vector<unique_ptr<char>> vec1 (move(vec)); //ok
  Bar bar(vec1);
  return 0;
}
like image 648
Agrim Pathak Avatar asked Dec 25 '22 01:12

Agrim Pathak


2 Answers

This code works fine for me:

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

struct Bar
{
    Bar(vector<unique_ptr<char>> vec)
        : Vec(move(vec))
    { }

    vector<unique_ptr<char>> Vec;
};

int main()
{
    vector<unique_ptr<char>> vec;
    vec.push_back(unique_ptr<char>(new char('a')));
    vec.push_back(unique_ptr<char>(new char('b')));
    vec.push_back(unique_ptr<char>(new char('c')));

    vector<unique_ptr<char>> vec1(move(vec));

    Bar bar(move(vec1));
}

Note that I removed the const in the constructor parameter, and I also added an explicit move when constructing bar in main().

In fact, you had this code in main():

vector<unique_ptr<char>> vec1 (move(vec)); //ok
Bar bar(vec1);

But that code required a copy of the vec1 vector when constructing bar. Since vec1 is defined as a vector of unique_ptrs, and since unique_ptr is movable but not copyable, the compiler issued an error: it is not possible to copy the vec1 vector.

Instead, you must be explicit in calling std::move() on the vec1 argument if you want to trigger a move of the vector argument.

like image 38
Mr.C64 Avatar answered Dec 27 '22 16:12

Mr.C64


The following should compile fine:

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

using namespace std;

class Bar
{
public:
  Bar(vector<unique_ptr<char>> vec);
  vector<unique_ptr<char>> vec_;
};

Bar::Bar(vector<unique_ptr<char>> vec) : // If you intend to move something,
                                         // do not make it const, as moving
                                         // from it will in most cases change
                                         // its state (and therefore cannot be
                                         // const-qualified).
  vec_(move(vec))
{
}

int main()
{
  vector<unique_ptr<char>> vec;
  vec.push_back(unique_ptr<char>(new char('a')));
  vec.push_back(unique_ptr<char>(new char('b')));
  vec.push_back(unique_ptr<char>(new char('c')));
  vector<unique_ptr<char>> vec1 (move(vec));
  Bar bar(std::move(vec1)); // Just like the line immediately above,
                            // the explicit `move` is required, otherwise
                            // you are requesting a copy, which is an error.
  return 0;
}

I have left the rest of your code unchanged, but you may want to read Why is “using namespace std;” considered bad practice?

like image 107
user703016 Avatar answered Dec 27 '22 14:12

user703016