存在引用时的赋值运算符和复制构造函数

Ash*_*sha 10 c++ assignment-operator default-copy-constructor

我只是使用此代码试验参考:

class A
{
};

class B
{
public:
    B(A& a): m_a(a){}

    A& m_a;
};

int main()
{
    A a;
    B b(a);
    B b1 = b;
}
Run Code Online (Sandbox Code Playgroud)

我期待两者都B b1 = b;产生错误.相反,当我使用VS2008编译时,我只是收到警告

警告C4512:'B':无法生成赋值运算符

我理解为什么我会收到这个警告.但是编译器不应该为B b1 = b;语句生成错误吗?它就像它生成了复制构造函数但没有生成赋值运算符.这两者本身并不相互联系吗?当另一个无法生成时,为其中一个生成默认实现是否有意义?

Alo*_*ave 11

warning C4512: 'B' : assignment operator could not be generated
Run Code Online (Sandbox Code Playgroud)

问题1:为什么会出现此警告?
引用只能在创建时初始化一次.您无法在创建后重新分配对另一个相同类型变量的引用,因为Reference只是为其创建的类型变量的别名,并将继续保持这样.尝试重新分配它会产生错误.
通常,编译器默认情况下会为每个类生成一个隐式位智能赋值运算符,但在这种情况下,因为它class B有一个引用作为成员m_a,如果编译器要生成一个隐式赋值运算符,它将破坏无法重新赋值引用的基本规则.因此编译器会生成此警告,通知您无法生成隐式赋值运算符.

问题2:但编译器不应该为B b1 = b生成错误; 声明呢?
生成的警告和此特定操作完全没有关系.
B b1 = b;调用隐式(由@AndreyT正确指出)复制构造函数B::B(const B&).隐式复制构造函数是类默认生成的成员函数之一.因此没有任何警告或错误.

问题3:它就像生成了复制构造函数但没有生成赋值运算符.这两者本身并不相互联系吗?
不,他们根本没有关系.是编译器生成了一个复制构造函数,但它无法生成一个赋值运算符,原因在于回答上面问题1中指定的原因.这是因为成员引用m_a可以在构造函数本身中初始化.它只是创建时的初始分配而不是分配的情况=.

问题4:当另一个无法生成时,是否只为其中一个生成默认实现是否有意义?
回答3问题似乎回答了这个问题.

只是重申代码示例中正在执行的操作:

B b(a);调用转换复制构造函数B::B(A&)
B b1 = b;调用默认的复制构造函数B::B(const B&)

考虑其他方案.
如果你有B b1 = a;它会调用B::B(A&),因此再没有错误.

但是如果B::B(A&)声明了explicit,编译器会标记一个错误,并且implicit conversions作为一个版本,编译器将不会允许任何错误conversion function.

这里检查一下.