【问题标题】:What is the distinction between implicitly-declared and implicitly-defined copy constructors?隐式声明和隐式定义的复制构造函数有什么区别?
【发布时间】:2014-11-26 18:31:09
【问题描述】:

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

关于隐式声明的复制构造函数和隐式定义的复制构造函数我已经阅读了 2 节,但我仍然不明白它们的区别。隐式声明但未定义的构造函数不会导致链接器问题吗?

规则非常复杂。我不记得 C++03 中有什么区别:要么你有一个编译器生成的复制构造函数,要么你没有。

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

【问题讨论】:

    标签: c++ copy-constructor


    【解决方案1】:

    如果有隐式声明的复制构造函数,它总是被定义1。其定义的选项是:

    • 已删除
    • 琐碎
    • 隐式定义

    如果程序尝试使用定义为已删除的构造函数,则该程序格式错误(即,您会遇到编译器错误)。在其他情况下,调用该函数。

    您链接的页面描述了上述三个选项中的每一个在哪些情况下发生。

    C++11 添加了deleted 函数的概念,用于当您想要明确地使类不可复制(等)时。您将其复制构造函数定义为已删除,然后如果有人试图复制您的对象,编译器会生成错误。

    普通可复制和不可普通复制之间的区别一直存在,但并没有说得那么清楚;您从 POD 的规则中推断出在哪些情况下允许使用 memcpy 复制对象。

    1正如 Brian 指出的那样,更准确的说法是 如果需要则定义。编译器从不隐式声明一个函数,然后生成一个链接错误。但是,如果函数定义不是成功构建可执行文件所必需的,那么它实际上不会费心形成定义。

    【讨论】:

    • 也许我被误导了,但声明是定义的一个子集。换句话说,如果定义了某些东西,它也会被声明。但是,如果声明了某些内容并不意味着它已定义(因此我们会说它已定义)
    • @void.pointer 你说的是用户提供的语法结构。这是在谈论编译器生成的构造函数。编译器永远不会在未定义函数的情况下隐式声明函数(好吧 - 正如 Brian 指出的那样,如果从未实际调用过,编译器就不会费心生成定义)。
    【解决方案2】:

    这在标准第 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 类型的对象,所有六个特殊成员函数(默认构造函数、析构函数、复制构造函数、移动构造函数、复制赋值运算符、移动赋值运算符)都被隐式声明为默认值,但未定义自它们没有被 ODR 使用。

    【讨论】:

    • 非常棒的解释。我希望看到更多将隐式声明与其他已删除/隐式定义/琐碎情况相结合的不同场景的示例。
    猜你喜欢
    • 2018-06-11
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    • 2012-07-19
    • 2016-12-28
    • 1970-01-01
    • 2013-05-21
    • 2012-08-21
    相关资源
    最近更新 更多