【问题标题】:rule of five and implicitly deleted functions [duplicate]五规则和隐式删除函数[重复]
【发布时间】:2018-03-06 07:00:21
【问题描述】:

就我的理解而言,五法则是指导性法则。尽管如此,我已经看到编译器在某些情况下可能会隐式删除函数。比如定义move-ctor'时,会删除copy assignment/copy ctor'。

我想知道是否还有上述情况。也就是说,自定义函数在哪些场景下可以隐式删除其他函数?

谢谢

编辑:
引用一些涵盖该主题的来源也可以!

【问题讨论】:

  • 只有三个特殊成员总是被隐式声明,如果不是用户声明的话:复制构造函数、复制赋值和析构函数。如果操作不可用,它们的每个隐含声明都可能是已删除声明。
  • 所有这些都包含在 C++ 标准中,在 "special member functions" 下。只需在该部分中查找“已删除”一词即可。
  • 在某处有一个关于此的 nixe 矩阵(可能是某个会议上的演讲的一部分),但看在上帝的份上,我找不到正确的答案。
  • @aschepler,太棒了!谢谢!

标签: c++ c++11 rule-of-three


【解决方案1】:

对于所有“五个”,标准定义了它们将被隐式声明为删除的情况。我已经为您命名并引用了 C++ 标准N4659 中的相关部分:

  • (12.3.3) 定义联合时,可以隐式删除五个联合中的一些:

    [..] [注意:缺少默认成员 初始化程序 (12.2),如果联合的任何非静态数据成员具有非平凡的默认构造函数 (15.1),则复制 构造函数 (15.8), 移动构造函数 (15.8), 复制赋值运算符 (15.8), 移动赋值运算符 (15.8), 或析构函数(15.4),联合的相应成员函数必须是用户提供的,否则将 为联合隐式删除 (11.4.3) — 尾注]

  • (15.1) 当没有用户定义的替代时,隐式声明“五”:

    默认构造函数(15.1)、拷贝构造函数和拷贝赋值运算符(15.8)、移动构造函数 和移动赋值运算符(15.8)和析构函数(15.4)是 特殊成员函数 . [ 笔记: 这 当程序不声明时,实现将为某些类类型隐式声明这些成员函数 明确声明它们。如果它们被 odr-used (6.2),实现将隐式定义它们。见 15.1, 15.4 和 15.8。 ——尾注 ]

  • (15.1.1) 构造函数的隐式删除:

    如果满足以下条件,则将类 X 的默认默认构造函数定义为已删除:
    — (5.1) X 是一个联合,它有一个带有非平凡默认构造函数的变体成员,并且 X 的任何变体成员都没有默认成员初始值设定项,
    — (5.2) X 是一个非联合类,它有一个变体成员 M 和一个非平凡的默认构造函数,并且包含 M 的匿名联合的变体成员没有一个默认成员初始化器,
    — (5.3) 任何没有默认成员初始值设定项 (12.2) 的非静态数据成员都是引用类型,
    — (5.4) 任何没有大括号或相等初始化器的 const 限定类型(或其数组)的非变体非静态数据成员都没有用户提供的默认构造函数,
    — (5.5) X 是一个联合,它的所有变体成员都是 const 限定类型(或其数组),
    — (5.6) X 是一个非联合类,任何匿名联合成员的所有成员都是 const 限定类型(或其数组),
    — (5.7) 任何可能构造的子对象,除了带有大括号或等号初始化器的非静态数据成员外,都具有类类型 M(或其数组),并且 M 没有默认构造函数或重载决议(16.3)为应用于查找 M 的对应构造函数会导致歧义或导致从默认默认构造函数中删除或无法访问的函数,或
    — (5.8) 任何可能构造的子对象都有一个带有析构函数的类型,该析构函数已从默认的默认构造函数中删除或无法访问

  • (15.8.1.10) 隐式删除复制/移动构造函数:

    如果 X 具有以下属性,则类 X 的默认复制/移动构造函数被定义为已删除 (11.4.3):
    — (10.1) 具有非平凡对应构造函数的变体成员,并且 X 是类联合类,
    — (10.2) 一个潜在构造的子对象类型 M (或其数组) 不能被复制/移动,因为重载决议 (16.3) 应用于查找 M 的相应构造函数会导致歧义或函数被删除或无法访问来自默认构造函数,
    — (10.3) 任何可能构造的具有析构函数的类型的子对象,该析构函数已从默认构造函数中删除或不可访问,或者,
    — (10.4) 对于复制构造函数,右值引用类型的非静态数据成员。定义为已删除的默认移动构造函数被重载决议(16.3、16.4)忽略。 [注意:删除的移动构造函数会干扰右值的初始化,而右值可以使用复制构造函数。 ——尾注]

  • (15.8.2) 隐式删除复制/移动赋值运算符:

    如果 X 具有以下条件,则将类 X 的默认复制/移动赋值运算符定义为已删除:
    — (7.1) 具有非平凡对应赋值运算符的变体成员,并且 X 是类联合类,或
    — (7.2) const 非类类型(或其数组)的非静态数据成员,或
    — (7.3) 引用类型的非静态数据成员,或
    — (7.4) 类类型 M(或其数组)的直接非静态数据成员或由于重载决议 (16.3) 而无法复制/移动的直接基类 M,用于查找 M 的相应赋值运算符,导致从默认赋值运算符中删除或无法访问的歧义或函数。

  • (15.4.5) 隐式删除析构函数:

    如果满足以下条件,则将类 X 的默认析构函数定义为已删除:
    — (5.1) X 是一个类联合类,它有一个变体成员和一个非平凡的析构函数,
    — (5.2) 任何可能构造的子对象都具有类类型 M(或其数组),并且 M 具有已删除的析构函数或无法从默认析构函数访问的析构函数,
    — (5.3) 或者,对于虚拟析构函数,查找非数组释放函数会导致歧义或导致从默认析构函数中删除或无法访问的函数。

【讨论】:

  • 非常感谢!
猜你喜欢
  • 2018-10-25
  • 2013-06-13
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
  • 2022-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多