Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 261
Nick Avatar asked Jul 03 '12 20:07

Nick


3 Answers

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.)

like image 175
James McNellis Avatar answered Nov 08 '22 20:11

James McNellis


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).

like image 31
Xeo Avatar answered Nov 08 '22 19:11

Xeo


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

like image 24
John Dibling Avatar answered Nov 08 '22 20:11

John Dibling