如果类具有引用数据成员,为什么默认赋值运算符不由编译器合成

时间:2012-05-28 07:51:59

标签: c++

在C ++中,如果类具有引用数据成员,则默认赋值运算符不由编译器合成。为什么?

2 个答案:

答案 0 :(得分:6)

  

在C ++中,如果类具有引用数据成员,则默认赋值运算符不由编译器合成。为什么?

副本分配的作用定义如下:

C ++ 03标准12.8 / 13:

  

每个子对象都以适合其类型的方式分配:

     
      
  • 如果子对象是类类型,则使用该类的复制赋值运算符(就好像通过显式限定;即忽略更多派生类中的任何可能的虚拟覆盖函数);

  •   
  • 如果子对象是一个数组,则以适合于元素类型的方式分配每个元素;

  •   
  • 如果子对象是标量类型,则使用内置赋值运算符。

  •   

简而言之,暗示 每个成员都应以适当的方式分配
提出了这个问题,
在课程中分配参考成员的行为应该是什么?
请考虑以下有关参考文献:

  1. 引用本身是不可转让的,它们一直引用与它们初始化相同的引用 [Ref 1]
  2. 由于#1分配给引用不会重新分配引用,它会更改引用的值,这是非直观的行为。
  3. 这里没有要执行的默认正确行为,而是一个相当情境化的行为。因此,C ++标准要求类的设计者最有能力确定此行为,因此决定默认赋值运算符不应由编译器,如果类具有引用数据成员。

    该决定载于:
    C ++ 03标准12.8 / 12:

      

    当为其类类型的对象分配其类类型的值或从其类类型派生的类类型的值时,隐式定义隐式声明的复制赋值运算符。如果隐式定义了复制赋值运算符的类具有以下内容,则程序生成错误:
       .......
        - 引用类型的非静态数据成员,或
       .......


    [参考1]
    C ++ 03标准8.5.3 / 2:

      

    初始化后无法更改引用以引用其他对象。请注意,引用的初始化与赋值的处理方式非常不同。参数传递(5.2.2)和函数值返回(6.6.3)是初始化。

答案 1 :(得分:4)

在仅限会员的论坛上看到了讨论。由于答案并不为大多数程序员所熟知,因此想发布答案并在此处分享。

来自C ++标准草案N3337§12.8.23:

  

如果X具有:

,则将类X的默认复制/移动赋值运算符定义为已删除      
      
  • 具有非平凡对应赋值运算符且X为a的变体成员   类似联盟的类,或
  •   
  • const非类类型(或其数组)的非静态数据成员,或
  •   
  • 引用类型的非静态数据成员,或
  •   
  • 类型M(或其数组)的非静态数据成员,不能是   复制/移动,因为重载分辨率(13.3),应用于M的相应   赋值运算符,导致歧义或删除的函数或   默认分配操作员无法访问,或
  •   
  • 由于过载而无法复制/移动的直接或虚拟基类B.   分辨率(13.3),应用于B的相应赋值运算符,得到   从默认情况下删除或无法访问的歧义或功能   赋值运算符,或
  •   
  • 用于移动赋值运算符,非静态数据成员或直接基类   使用没有移动赋值运算符的类型并且不是一般的   可复制的,或任何直接或间接的虚拟基类。
  •