【问题标题】:Why C++ compiler does not delete copy constructor when class has reference member? [duplicate]当类具有引用成员时,为什么 C++ 编译器不删除复制构造函数? [复制]
【发布时间】:2019-06-18 14:23:40
【问题描述】:

C++ 编译器不会为具有引用成员的类提供默认的复制赋值运算符(以及其他一些场景)。 原因是,如果提供了默认的复制赋值运算符,那么源对象和目标对象的引用成员都引用同一个副本。

但是,在相同的场景中提供了默认的复制构造函数,这引入了与提供默认的复制赋值运算符相同的问题。

提供默认复制构造函数的任何原因?

#include <iostream>
using namespace std;

class People{
public:
    People(string name = ""):m_name(name){
}
string getName(){
    return m_name;
}
void setName(string name){
    m_name = name;
}
private:
    string& m_name;//reference member
};

int main() {
    People a("Erik");
    People b(a);
    a.setName("Tom");
    cout << a.getName() << endl;//This prints "Tom"
    cout << b.getName() << endl;//This prints "Tom"
    //a = b; //Build error
    return 0;
}

【问题讨论】:

  • 未定义的行为可能会做一些令人惊讶的事情。
  • 注意 - 您正在获取构造函数的参数按值,然后保存对它的引用。如果您使用该引用,那将是未定义的行为。
  • "如果提供了默认的复制赋值运算符,那么源对象和目标对象的引用成员都指向同一个副本" 对不起,我不明白那句话。跨度>
  • 这一行:m_name = name; 在执行时是未定义的行为。那是因为m_name 是对已销毁对象的引用。您的代码编写方式表明您对引用是什么以及它们如何工作存在重大误解。
  • @Omnifarious 从技术上讲,如果您从不使用该引用,它真的是 UB 吗?

标签: c++ copy-constructor


【解决方案1】:

可以在复制构造函数中初始化引用,以引用与其他类实例中的引用相同的对象。但是一旦初始化,引用就不能被重新分配以引用不同的对象;所以赋值运算符不能保持类似于复制构造函数的语义。


您的示例将m_name 引用绑定到构造函数的参数,当构造函数返回时,该参数超出范围,使引用悬空。之后对m_name 的任何使用都会表现出未定义的行为。您不应根据该程序的行为得出任何结论。

【讨论】:

    【解决方案2】:

    当类有引用成员时,为什么 C++ 编译器不删除复制构造函数?

    因为引用是可复制的。

    如果提供了默认的复制赋值运算符,那么源对象和目标对象的引用成员都引用同一个副本。

    没有。无法提供隐式复制赋值运算符,因为无法将引用分配给另一个对象。

    【讨论】:

      猜你喜欢
      • 2019-06-16
      • 2017-07-20
      • 1970-01-01
      • 2019-03-15
      • 2019-01-04
      • 1970-01-01
      • 2012-11-28
      • 1970-01-01
      相关资源
      最近更新 更多