当返回作为const引用的字符串时,编译器是否避免复制?

Does the compiler avoid a copy when returning a string that is taken as const reference?

本文关键字:是否 编译器 复制 字符串 返回 const 引用      更新时间:2023-10-16

我想知道编译器是否会在以下情况下优化副本。我有一个类,它唯一的资源成员是一个可能有几KB大的字符串。我想让这个类的一个公共成员访问那个字符串,我不确定我应该让这个成员返回一个引用还是简单地按值返回。假设我选择按值返回

class A { 
  public: 
    A();
    ~A();
    std::string getString() { return str; } 
  private:
    std::string str;
} 
int main() { 
  A *a = new A;
  const std::string& str = a->getString();
  std::cout << str;
}

如果我把结果作为const std::string&作为main,编译器会优化和避免复制吗?

在这种情况下,编译器将优化掉一个副本的可能性很小,但可能性很小。

注意,如果副本被优化了,调用者的临时本质上被绑定为对对象的类成员的const引用。const表示参考值不可改变。

对于这个问题中所示的代码,编译器可以向自己证明,当const引用仍然在作用域内时,没有任何可能改变类成员的内容,因此进行此优化是安全的。

但在更普遍的情况下,事情很快就会变得混乱。如果有其他类方法可能改变被引用的类成员的内容,如果在const引用的生命周期内调用了定义不可见的函数或方法;最可能的结果是,编译器将无法知道是否有可能在const引用的整个执行范围内修改被引用的类成员,因此它将被迫复制字符串,以保证其const性。

编译器可以自由地只进行那些在格式良好的程序中不会导致可见的、可观察到的变化的优化。如果编译器不能证明优化结果没有可见的、可观察到的变化,那么优化将不会执行。

注:注意,"修改"也包括销毁。建议的优化将const引用绑定到动态范围内的对象。如果有任何对delete的中间调用——显式或隐式地作为调用各种库容器方法的一部分——编译器还必须向自己证明 deleted对象不能是绑定const引用的对象。