对象传参、返回与接收的优化

C++的编译器会给一个空的类提供六个函数

  • 默认构造函数
  • 析构函数
  • 拷贝构造
  • 拷贝赋值
  • 移动构造
  • 移动赋值

在提供构造函数时,编译器将不再提供默认构造。

这些函数在对象传参、返回对象、接收对象时会自动调用,所以有必要进行相应的优化,减少这种隐式调用。
以下面这段代码为例:

#include <iostream>
class Foo {
public:
  Foo(int a) : _a(a) { std::cout << "Foo(int)" << std::endl; }
  ~Foo() { std::cout << "~Foo()" << std::endl; }
  Foo(const Foo &val) : _a(val._a) {
    std::cout << "Foo(const Foo&)" << std::endl;
  }
  Foo(Foo &&val) : _a(val._a) { std::cout << "Foo(Foo&&)" << std::endl; }
  Foo &operator=(const Foo &val) {
    if (this == &val)
      return *this;
    _a = val._a;
    return *this;
  }
  Foo &operator=(Foo &&val) {
    if (this == &val)
      return *this;
    _a = val._a;
    return *this;
  }
  int getA() const { return _a; }

private:
  int _a;
};

Foo bar(Foo f) {  // 3. Foo(const Foo&)
  int a = f.getA();
  Foo tmp(a);
  return tmp;
}

Foo bar2(const Foo &f) { return Foo{f.getA()}; }

int main() {
  {
    // 优化前
    Foo f1(42);  // 1. Foo(int)
    Foo f2(10);  // 2. Foo(int)
    f2 = bar(f1);  // 4. Foo(int)
  }
  std::cout << "============================" << std::endl;
  {
    // 优化后
    Foo f3(42);  // 1. Foo(int)
    Foo f4 = bar2(f3);  // 2. Foo(int)
  }
}

运行结果如下:

eric@eric-XPS-13-9360:~/tmp$ g++ main.cpp 
eric@eric-XPS-13-9360:~/tmp$ ./a.out 
Foo(int)
Foo(int)
Foo(const Foo&)
Foo(int)
~Foo()
~Foo()
~Foo()
~Foo()
============================
Foo(int)
Foo(int)
~Foo()
~Foo()

不同编译器可能执行结果不同,对编译优化的设置也会影响运行结果。

优化效果还是很明显的,优化前有四次构造,对应四次析构,而优化后仅发生两次构造和析构。

主要理解以下三个优化规律:

  • 对象传参,使用&传递,在必要时加const修饰
  • 对象返回,获取成员后,通过构造函数直接返回临时对象
  • 对象接收,直接构造而不是通过赋值

在利用临时对象构造新对象时,编译器会自动优化,将临时对象的构造、新对象的拷贝构造优化为一次构造。
尽可能使用临时对象的直接构造,而不产生中间对象。

posted @ 2024-04-21 11:45  EricLing0529  阅读(4)  评论(0编辑  收藏  举报