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

C++ std::unique_ptr编译器错误:派生类的成员无法访问基类的私有成员,c++,c++11,compiler-errors,unique-ptr,C++,C++11,Compiler Errors,Unique Ptr,当我尝试编译以下代码时,我得到: #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;

当我尝试编译以下代码时,我得到:

#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;
}
#包括
#包括
使用名称空间std;
类数据
{
公众:
静态数据解析()
{
数据d;
数据分析(d);
返回d;
}
清单l;
私人:
静态void解析(数据和节点)
{       }
};
int main()
{
返回0;
}
为什么??我如何修复此问题?


注意:我可以使用
std::shared_ptr
而不是
std::unique_ptr

首先,VC++不会自动生成移动向量和移动赋值操作符,这意味着您需要自己定义它们

接下来,当您返回局部变量时,编译器首先尝试移动它们,然后再实际执行通常的复制路径。然而,要做到这一点,它需要采取行动。由于没有,它会尝试通常的复制,并通过生成的复制构造函数自动调用
std::list
的复制构造函数,该构造函数反过来尝试调用其元素类型的复制构造函数,在
std::unique_ptr
的情况下,该复制构造函数是私有的


您需要定义不调用
std::unique\u ptr
的复制ctor(即制作内容的深度副本)的适当移动ctor或复制ctor。

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

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

data& operator=(data&& other)
{
    l = std::move(other.l);
    return *this;
}
而且,由于您将添加一个用户声明的构造函数,因此还需要一个用户声明的默认构造函数:

data() { }
我的理解是,根据最终的C++11语言标准,您的代码是正确的。Visual C++没有完全实现最终的规范,当隐式地生成移动操作时(Visual C++ 2012 RC)。隐式移动操作何时生成的规范在标准化过程的后期多次更改

如果您有一个类类型“代码>代码>代码>,它具有任何可移动但不可复制的数据成员,VisualC++将不会生成隐式移动构造函数或移动赋值操作符,并且隐式复制构造函数和复制赋值运算符都被仅移动数据成员的存在所抑制。换句话说,如果您想要只聚合移动类型,您必须自己为聚合类提供移动操作

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

简短回答:
列表中的项目必须是可复制或可移动的。
unique\u ptr
设计上不可复制,但只要受控类型也是可移动的,它是可移动的

您的类型,
data
不可移动,因为您尚未实现移动语义,并且编译器没有为您执行此操作

实现移动语义,您可以在
列表中使用
unique\ptr

data(ddata&&) {};
根据该标准,编译器将为您的类生成一个move构造函数。然而,VS10不支持这一点——这可能是您遇到的问题


如需进一步参考,请参阅我在CR上的帖子:

请发布您的实际错误消息,以及足够的代码来重现它。@KerrekSB您可以使用更新进行测试,错误消息不是英文的,是否仍要查看?请尝试添加空正文默认构造函数,并添加一个复制构造函数。@Nick:您可以添加什么样的复制构造函数来做任何有意义的事情?@ildjarn我添加了
数据(const data&){}
和空的默认构造函数。我不知道移动构造函数和移动赋值运算符是什么,它们的作用是什么。你能解释一下吗?我不明白你答案的最后一段<代码>返回标准::移动(局部变量)在我知道的所有情况下都是错误的:它抑制NRVO,编译器在它们可用时更喜欢移动操作(VisualC++将在这种情况下正确地选择移动构造函数)。@杰姆斯:右,最后一段在我的编辑中幸存下来。修正了。我不知道移动向量和移动赋值操作符是什么,它们的作用是什么。你能解释一下吗?如果你想要一个聚合,你最好说
data()=default@KerrekSB:OP使用Visual C++,它不支持默认和删除的特殊成员函数。如果你使用的是一个神话般的编译器,它支持整个C++11并且没有任何bug,那么这些都不是必需的,代码应该是正常的。@JamesMcNellis:我明白了。太可惜了。@Nick:See
std::unique\u ptr
是一种只能移动的类型:你不能复制那种类型的对象,你只能移动它们。这是因为给定的
std::unique_ptr
对象是给定的
T
对象的唯一所有者(因此它的名称)。如果您可以复制它,那么它将不再是唯一的所有者(然后将有两个所有者)。无论“受控类型”如何,
unique\u ptr
始终是可移动的。