6

当我尝试编译以下代码时出现编译器错误 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.

4

3 回答 3

10

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

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++ 将不会生成隐式移动构造函数或移动赋值运算符,并且隐式复制构造函数和复制赋值运算符都会被 move- 的存在所抑制。唯一的数据成员。换句话说,如果您想要聚合仅移动类型,则必须自己为聚合类提供移动操作。

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

于 2012-07-03T20:20:31.597 回答
5

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

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

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

于 2012-07-03T20:16:12.623 回答
2

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

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

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

data(ddata&&) {};

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

如需进一步参考,请参阅我在 CR 上的帖子:移动语义的规范实现

于 2012-07-03T20:21:19.100 回答