【问题标题】:std::unique_ptr compiler error: Members of a derived class cannot access private members of a base classstd::unique_ptr 编译器错误:派生类的成员不能访问基类的私有成员
【发布时间】:2012-07-03 20:01:20
【问题描述】:

当我尝试编译以下代码时,我得到Compiler Error 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;
}

为什么?我该如何解决这个问题?

注意:我使用std::shared_ptr 代替std::unique_ptr 没有问题。

【问题讨论】:

  • 请发布您的实际错误消息,以及足够的代码来重现它。
  • @KerrekSB 你可以用更新测试一下,报错信息不是英文的,你还要看吗?
  • 尝试添加一个空体默认构造函数,并添加一个复制构造函数。
  • @Nick : 你可以添加什么复制构造函数来做有意义的事情?
  • @ildjarn 我添加了data(const data&amp;){} 和空的默认构造函数。

标签: c++ c++11 compiler-errors unique-ptr


【解决方案1】:

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

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 开始)。在标准化过程的后期,何时生成隐式移动操作的规范发生了多次更改。

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

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

【讨论】:

  • 我不知道什么是移动 ctor 和移动赋值运算符以及它们的用途。你能解释一下吗?
  • 如果你想要一个聚合,你最好说data() = default;
  • @KerrekSB:OP 使用的是 Visual C++,它不支持默认和删除的特殊成员函数。如果一个人正在使用一个支持整个 C++11 并且没有错误的神话编译器,那么这一切都不是必需的,代码应该是原样的。
  • @JamesMcNellis:我明白了。真可惜。
  • @Nick:见Can someone please explain move semantics to me? std::unique_ptr&lt;T&gt; 是只移动类型:您不能复制该类型的对象,只能移动它们。这是因为给定的std::unique_ptr&lt;T&gt; 对象是给定T 对象的唯一所有者(因此得名)。如果您可以复制它,那么它将不再是唯一所有者(将有两个所有者)。
【解决方案2】:

首先,VC++ 还没有自动生成移动 ctor 和移动赋值运算符,这意味着你需要自己定义它们。

接下来,当您返回局部变量时,编译器首先会尝试移动它们,然后才能真正按照通常的方式复制它们。但是,要做到这一点,它需要一个移动 ctor。因为它没有,它尝试通常的复制并通过生成的复制ctor自动调用std::list的复制构造函数,后者又尝试调用其元素类型的复制ctor,它在std::unique_ptrs中是私有的案例。

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

【讨论】:

  • 我不知道什么是移动 ctor 和移动赋值运算符以及它们的用途。你能解释一下吗?
  • 我不明白你回答的最后一段。 return std::move(local_variable); 在我知道的所有情况下都是不正确的:它抑制 NRVO,并且编译器应该更喜欢移动操作而不是复制操作(在这种情况下,Visual C++ 将正确选择移动构造函数)。
  • @James:是的,最后一段在我的编辑中幸存下来。固定。
【解决方案3】:

简短回答:(特定于 C++11)list 中的项目必须是可复制或可移动的。 unique_ptr 在设计上是不可复制的,但它是可移动的,只要受控类型也是可移动的。

您的类型data 是不可移动的,因为您没有实现移动语义并且编译器没有为您实现。

实现移动语义,您可以在list 中使用unique_ptr

data(ddata&&) {};

根据标准,编译器将为您的类生成一个移动构造函数。但是,VS10 不支持这一点——这可能是您遇到的问题。

如需进一步参考,请参阅我在 CR 上的帖子:Canonical Implementation of Move Semantics

【讨论】:

  • A unique_ptr总是可移动的,无论“受控类型”如何。
猜你喜欢
  • 2018-04-19
  • 1970-01-01
  • 2017-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-16
相关资源
最近更新 更多