隐式声明和隐式定义的复制构造函数有什么区别?

15

我正在查看cppreference关于复制构造函数的页面: http://en.cppreference.com/w/cpp/language/copy_constructor

我已经多次阅读有关隐式声明和隐式定义复制构造函数的两个部分,但我仍然不理解区别。 隐式声明而未定义的构造函数会导致链接器问题吗?

规则非常复杂。 我不记得在C++03中有任何区别:您要么具有编译器生成的复制构造函数,要么不具有。

可以有人用更简单的话来解释一下这两个类别之间的区别/差异吗?


(Note: 保留了html标签)
2个回答

12

这在第12款的开头有一个注释进行了澄清:

[ 注: 当程序没有显式声明某些类类型的成员函数时,实现将隐式地为其声明这些成员函数。如果它们被odr-used (3.2),则实现将隐式地定义它们。请参见12.1、12.4和12.8。— 注解结束 ]

C++14(N3936)的规范引用分别是12.1/5、12.4/6、12.8/13和12.8/26。在每种情况下,如果相应的特殊成员函数被默认并且未定义为删除,则会隐式定义它,并且必须odr-used或显式地默认。如果我们有类似以下代码:

struct Foo {};

并且不会创建任何Foo类型的对象,所有六个特殊成员函数(默认构造函数、析构函数、拷贝构造函数、移动构造函数、拷贝赋值运算符、移动赋值运算符)都会被隐式声明为=default,但是由于它们没有被odr-used,因此它们不会被定义。


1
非常棒的解释。我很想看到更多将隐式声明与其他已删除/隐式定义/琐碎情况相结合的不同场景示例。 - void.pointer

4
如果有一个隐式声明的复制构造函数,则始终会定义它1。其定义选项为:
  • 删除
  • 平凡
  • 隐式定义
如果程序尝试使用被定义为删除的构造函数,则程序是非法的(即您会得到编译器错误)。在其他情况下,将调用该函数。
链接的页面描述了每个选项发生的情况。
C++11添加了“已删除”函数的概念,用于使类明确为不可复制(等等)。您将其复制构造函数定义为已删除,然后如果有人尝试复制您的对象,则编译器会生成错误。
“平凡可复制”和“不平凡可复制”的区别一直存在,但并没有说明得那么清楚;您可以从POD的规则中推断出在哪些情况下允许使用memcpy来复制对象。 1正如Brian指出的那样,更准确的说法是:如果需要,则定义它。编译器永远不会隐式声明函数,然后生成链接错误。但是,如果不需要函数定义就可以成功构建可执行文件,则不会费心形成定义。

也许我有所误解,但声明是定义的子集。换句话说,如果某物被定义了,它也被声明了。然而,如果某物被声明了,并不意味着它被定义了(因此我们会说它被定义了)。 - void.pointer
1
@void.pointer,你在谈论用户提供的语法结构。这是在谈论编译器生成的构造函数。编译器从不隐式声明未定义的函数(好吧 - 正如Brian指出的那样,如果从未实际调用,则编译器不会费心生成定义)。 - M.M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接