Nick
Nick

Reputation: 10499

std::unique_ptr compiler error: Members of a derived class cannot access private members of a base class

I get Compiler Error C2248 when i try to compile the following code:

#include <list>
#include <memory>
using namespace std;


class data
{
public:

    static data parse()
    {
        data d;
        data::parse(d);
        return d;
    }

    list<std::unique_ptr<data>> l;

private:

    static void parse(data& node)
    {       }
};


int main()
{

    return 0;
}

Why? How can i fix this?

Note: I have no problem using std::shared_ptr instead of std::unique_ptr.

Upvotes: 6

Views: 1882

Answers (3)

Xeo
Xeo

Reputation: 131809

First things first, VC++ doesn't automatically generate a move ctor and move assignment operator yet, which means you need to define them yourself.

Next, when you return local variables, the compiler first tries to move them before actually going the usual route of copying them. However, to do that, it needs a move ctor. Since it doesn't have that, it tries the usual copy and through the generated copy ctor automatically invokes the copy constructor of std::list which in turn tries to invoke the copy ctor of its element type, which is private in std::unique_ptrs case.

You need to either define an appropriate move ctor or a copy ctor that doesn't invoke std::unique_ptr's copy ctor (i.e., make a deep copy of the content).

Upvotes: 5

James McNellis
James McNellis

Reputation: 355079

You need to provide move operations for your type:

data(data&& other)
    : l(std::move(other.l))
{
}

data& operator=(data&& other)
{
    l = std::move(other.l);
    return *this;
}

And, since you'll have added a user-declared constructor, you'll also need a user-declared default constructor:

data() { }

My understanding is that your code is correct as-is, per the final C++11 language standard. Visual C++ does not fully implement the final specification for when move operations are implicitly generated (as of the Visual C++ 2012 RC). The specification for when implicit move operations are generated changed several times very late in the standardization process.

If you have a class type C that has any data member that is movable but noncopyable, Visual C++ will not generate an implicit move constructor or move assignment operator, and the implicit copy constructor and copy assignment operator are both suppressed by the presence of the move-only data member. In other words, if you want ot aggregate move-only types, you must provide the move operations for the aggregating class yourself.

(At least, this is my understanding from experimentation with the compiler.)

Upvotes: 10

John Dibling
John Dibling

Reputation: 101456

Short answer: (C++11 specific) Items in a list must be copyable or movveable. A unique_ptr is not copyable by-design, but it is moveable, so long as the controlled type is also moveable.

Your type, data is not moveable because you have not implemented move semantics and the compiler did not do it for you.

Implement move semantics, and you can use unique_ptr in a list:

data(ddata&&) {};

According to thhe Standard, a move constructor would be generated for your class by the compiler. However, VS10 does not support this -- this might be the problem your'e running in to.

For further reference, see my post on CR: Canonical Implementation of Move Semantics

Upvotes: 2

Related Questions