std :: unique_ptr编译器错误:派生类的成员无法访问基类的私有成员

Nic*_*ick 6 c++ compiler-errors unique-ptr c++11

当我尝试编译以下代码时,我得到编译器错误C2248:

#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;
}
Run Code Online (Sandbox Code Playgroud)

为什么?我怎样才能解决这个问题?

注意:我没有问题std::shared_ptr而不是使用std::unique_ptr.

Jam*_*lis 10

您需要为您的类型提供移动操作:

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

data& operator=(data&& other)
{
    l = std::move(other.l);
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

而且,既然你已经添加了一个用户声明的构造函数,那么你还需要一个用户声明的默认构造函数:

data() { }
Run Code Online (Sandbox Code Playgroud)

根据最终的C++ 11语言标准,我的理解是你的代码是正确的.Visual C++没有完全实现隐式生成移动操作的最终规范(从Visual C++ 2012 RC开始).生成隐式移动操作的规范在标准化过程中很晚就改变了几次.

如果您的类类型C具有可移动但不可复制的任何数据成员,则Visual C++将不会生成隐式移动构造函数或移动赋值运算符,并且隐式复制构造函数和复制赋值运算符都会因移动的存在而被抑制 -只有数据成员.换句话说,如果您不想要聚合仅移动类型,则必须自己为聚合类提供移动操作.

(至少,这是我对编译器实验的理解.)

  • @KerrekSB:OP使用的是Visual C++,它不支持默认和删除的特殊成员函数.如果一个人正在使用支持整个C++ 11并且没有错误的神秘编译器,那么这一切都不是必需的,代码应该是正常的. (3认同)

Xeo*_*Xeo 5

首先,VC++不会自动生成移动ctor并移动赋值运算符,这意味着您需要自己定义它们.

接下来,当您返回局部变量时,编译器首先尝试在实际执行复制它们的常规路径之前移动它们.但是,要做到这一点,它需要一个移动ctor.由于它没有那个,它尝试通常的副本并通过生成的副本ctor自动调用复制构造函数,std::list而复制构造函数又试图调用其元素类型的复制文件,这在某种std::unique_ptr情况下是私有的.

您需要定义一个适当的移动ctor或一个不调用std::unique_ptr复制文件的复制文件(即,制作内容的深层副本).