2013-03-28 48 views
0

我有一个树类,它具有移动构造函数和移动赋值运算符声明和定义。复制构造函数...一个困惑

为什么编译器会觉得需要合成一个拷贝构造函数,然后抱怨std::unique_ptr有私有成员?

这似乎适得其反。编译器是否应该意识到隐藏的副本和任务没有主体或者没有定义是为了防止尝试复制std::unique_ptr

而且,为什么声明和定义具有空体的复制构造函数和赋值运算符会使编译器感到高兴?

在我继续使用这个类编写和构建代码时,这会引起关注吗?

附加

  1. 没有源代码,因为没有源代码中的错误......这是一个问题
    不需要的源代码存在。

  2. 编译器抱怨拷贝构造函数是私人的,所以我把它们公开; 将再次私有并验证编译器是否支持小应用程序。

  3. 我使用的是Visual Studio 2012 Professional IDE及其相关的编译器。

为什么编译器在存在移动构造函数时会生成复制构造函数?似乎违反直觉,特别是如果复制构造函数没有在第一个地方定义。

其它问题

好吧,看来的Visual Studio 2012不支持=在构造函数或赋值操作符和隐藏我的声明导致编译器在我的代码全部删除哭声明。现在我该怎么做?我同意(下文)宣布不做任何事情的拷贝构造函数是个坏主意,那么我还有其他什么选择?

如果真的需要小例子,这里是。我的编译器不支持=删除

class Tree{ 
    class TreeNode{ 
     "declaration of unique_ptr, cstrs, move cstrs, hidden copy cstrs" 
    }; 
public: 
    "declaration of unique_ptrs, cstrs, move cstrs, copy cstrs <----- compiler 
     complains if hidden" 
}; 

使用boost ::变种与此

+4

请显示您的C++源代码(或与其等效的小示例) –

+0

编译器只会在您实际尝试复制或复制分配时抱怨,这是非常合理的。 – juanchopanza

+0

如果你想确保没有人使用复制构造函数和赋值操作符,你可以将它们定义为private或(=在C++ 11中删除) – kalvis

回答

2

如果没有一个拷贝构造函数,编译器将尝试生成一个。默认的拷贝构造函数非常愚蠢,所以它不会让你感到惊讶,它会跳过你的类的一些部分。

定义一个空的给你一个不做任何事情的拷贝构造函数,这代替了编译器本来会生成的那个,从而避免了这个问题。

+3

如果复制构造函数不创建副本,它不完全*避免*问题。你只是为了解决其他问题而进行交易。 –

+3

你不想要一个可以调用的空副本构造函数:这可能会导致相当令人惊讶的行为。隐藏或删除它... – Yakk

+0

@Yakk:或者让编译器隐式删除它。如果存在移动构造函数或不可复制的成员,则会发生这种情况,这两种情况似乎都是这种情况。 –

1

为什么编译器会觉得需要综合复制构造函数,然后抱怨std::unique_ptr有私有成员?

它不应该,除非你的标准库不兼容,并且为unique_ptr声明一个私有的而不是被删除的拷贝构造函数;即使这样,如果你还没有声明移动构造函数,它也应该被合成。

如果你的类有unique_ptr成员,或者你声明了一个移动构造函数,那么它应该抱怨复制构造函数被删除;然后只有当你写代码试图复制它。

如果编译器不知道隐藏的副本和赋值没有主体或者没有定义是为了防止尝试复制std::unique_ptr

没错;除了合成的拷贝构造函数和赋值被删除,而不是未定义。

而且,为什么声明和定义具有空体的拷贝构造函数和赋值运算符会使编译器感到高兴?

因为您明确表示您希望它使用该(空)代码进行复制,而不是隐式生成的任何代码(而不是代码)。尽管这是一个糟糕的主意;如果你的类不可复制,那么你需要尝试复制它来产生错误,而不是错误的运行时行为。

+0

移动构造函数的存在不会自动抑制拷贝构造函数的生成吗? –

+0

@DavidRodríguez-dribeas:差不多;它会被宣布但被删除。我会更新我的答案...... –

+0

@MikeSeymour是......'= delete',如果我记得,语法是MyCopyConstructor(const MyCopyCOnstructor&other)= delete'。是对的吗? – Mushy