lundi 25 septembre 2017

unique_ptr passed as arguments to a constructor

Recently I posted a question about smart pointers. From the answers, I have tried to implement this class:

class Bar;
class Baz;

class Foo
{
public:
    Foo(std::unique_ptr<Bar> param1, std::vector<std::unique_ptr<Baz>> param2);

    virtual ~Foo();

    // Method using myBar and myBaz polymorphically...

private:
    std::unique_ptr<Bar>               myBar;
    std::vector<std::unique_ptr<Baz>>  myBaz;
};

The constructor is implemented this way:

Foo(std::unique_ptr<Bar> param1, std::vector<std::unique_ptr<Baz>> param2):
    myBar{std::move(param1)},
    myBaz{std::move(param2)}
{
    // Throws exception if some conditions are not met.
}

I made sure, in order to be able to use move semantics, to pass the pointers by value and to use std::move. Both Bar and Baz are copyable and movable. Since I have never implemented something of the sort before, I wanted to unit test it before moving further. Using the GoogleTest framework, I wrote this test:

TEST(Foo, Constructor)
{
    std::vector<std::unique_ptr<Baz>> myVec;
    myVec.push_back(std::make_unique<Baz>());
    myVec.push_back(std::make_unique<Baz>());
    myVec.push_back(std::make_unique<Baz>());

    ASSERT_NO_THROW((Foo{myVec, std::make_unique<Bar>()}));
}

Which does not compile with gcc 7.1. The error message is very nasty but seems to point out that some illegal copy happens with myVec. As a side note, make_unique is available on my system since I compile with the --std=c++14 flag enabled.

I decided to try something and change my test like so:

TEST(Foo, Constructor)
{
    std::vector<std::unique_ptr<Baz>> myVec;
    myVec.push_back(std::make_unique<Baz>());
    myVec.push_back(std::make_unique<Baz>());
    myVec.push_back(std::make_unique<Baz>());

    ASSERT_NO_THROW((Foo{std::move(myVec), std::make_unique<Bar>()}));
}

Notice the vector is now moved into the constructor. This takes care of the copying problem and the code compiles and links fine, but then I get a segmentation fault runtime error on my test executable.

Questions:

  1. Why do I need to std::move the vector twice (once in the test, once in the initialization list) for the code to compile. Is it because the first time I move (cast) into param1 and then I move into myBaz?
  2. What is up with the segmentation fault?

Any advice on how to do this properly is welcome of course and if you need it, I can provide the compile error gcc produced, but it is pretty cumbersome, as mentioned above.

Aucun commentaire:

Enregistrer un commentaire