从函数和复制构造函数返回的对象

Object returned from function and copy constructor

本文关键字:返回 对象 构造函数 复制 函数      更新时间:2023-10-16

有这样的代码:

#include <iostream>
class A {
public:
    int a;
    A() : a(0) {
        std::cout << "Default constructor" << " " << this << std::endl;
    }
    A(int a_) : a(a_) {
        std::cout << "Constructor with param " << a_ << " " << this << std::endl;
    }
    A(const A& b) {
        a = b.a;
        std::cout << "Copy constructor " << b.a << " to " << a << " " << &b << " -> " << this << std::endl;
    }
    A& operator=(const A& b) {
        a=b.a;
        std::cout << "Assignment operator " << b.a << " to " << a << " " << &b << " -> " << this <<  std::endl;
    }
    ~A() {
        std::cout << "Destructor for " << a << " " << this << std::endl;
    }
    void show(){
      std::cout << "This is: " << this << std::endl;
    }
};

A fun(){
  A temp(3);
  temp.show();
  return temp;
}

int main() {
    {
      A ob = fun();
      ob.show();
    }
    return 0;
}
结果:

Constructor with param 3 0xbfee79dc
This is: 0xbfee79dc
This is: 0xbfee79dc
Destructor for 3 0xbfee79dc

对象ob由函数fun()初始化。为什么这里没有调用复制构造函数?我认为,当函数返回值,然后复制构造函数或赋值操作符被调用。似乎在函数fun()中构造的对象在函数执行后不会被销毁。在这种情况下,如何强制调用复制构造函数?

为什么这里没有调用复制构造函数?

RVO

在这种情况下如何强制调用复制构造函数?

传递一个选项给编译器。对于gcc,禁用RVO

--no-elide-constructors选项。

这被称为命名返回值优化复制省略,基本上意味着编译器已经发现可以通过小心地将临时对象和对象放在相同的内存位置来避免复制。

默认情况下,这段代码中有三个对象,tempfun中,返回值和ob在main中,以及多达两个副本,但是通过小心地将temp放置在与fun中返回对象相同的内存位置中,并将ob放置在相同的内存地址中,可以优化两个副本。

我写了关于这两个优化的一些图片来解释这里发生了什么:

  • NRVO
  • 复制省略