跳到内容

优化 C++/代码优化/构造和析构

来自 Wikibooks,开放世界中的开放书籍

通常情况下,在处理表达式时,会创建一个临时对象,该对象在表达式结束时被销毁。如果该对象是基本类型,编译器几乎总是能够避免其创建,而且基本类型对象的创建和销毁速度相当快。相反,如果该对象是复合类型,其创建和销毁成本无限,因为它们会导致构造函数和析构函数的调用,这些函数可能需要任何时间。

在本节中,将介绍一些避免创建复合临时对象的技术,从而避免调用其构造函数和析构函数。

函数返回值

[编辑 | 编辑源代码]

对于非内联函数,尝试声明一个返回值类型,其对象复制移动不超过 8 字节。如果不可行,至少在 `return` 语句中构造结果对象。

在编译非内联函数时,编译器无法知道返回值是否会被使用,因此必须生成它。生成和分配一个复制移动不超过 8 字节的对象几乎没有成本,但生成和分配更复杂的对象则需要时间。如果临时对象拥有资源,所花费的时间会更大,但即使没有分配,所花费的时间也会随着该对象所使用的机器字的数量而增加。

然而,如果要返回的对象是在 `return` 指令本身中构造的,因此没有将该值分配给变量,那么语言标准保证了一种称为 _返回值优化_ 的优化,它可以阻止创建临时对象。

一些编译器可以成功地避免创建临时对象,即使返回的对象与局部变量相关联(使用所谓的 _命名返回值优化_),但这通常没有保证,并且有一些限制。 C++ 常见问题解答

要检查是否应用了上述优化之一,请在返回对象类的每个构造函数、析构函数和赋值运算符中递增一个静态容器。如果没有应用任何优化,请使用以下替代技术之一

  • 将 `void` 设为函数返回类型,并向其添加一个按引用传递的参数,充当返回值。
  • 将函数转换为返回类型的构造函数,接受相同的函数参数。
  • 使函数返回一个辅助类型的对象,该对象从返回值对象中窃取资源,并将它们传递给目标对象,而无需复制其内容。
  • 使用一个 _表达式模板_,这是一种高级技术,是称为 _模板元编程_ 的编程范式的组成部分。
  • 如果使用 C++11 标准,请使用 _右值引用_。

将声明移出循环

[编辑 | 编辑源代码]

如果在循环体中声明了一个变量,并且对其进行赋值的成本小于构造和析构的成本,请将该声明移到循环之前。

如果在循环体中声明了该变量,则相关联的对象会在每次迭代时构造和析构,而如果它在循环之外,则该对象只构造和析构一次,但在循环体中可能会多赋值一次。

不过,在很多情况下,赋值的成本与构造和析构对的成本完全相同,因此在这种情况下,将声明移出循环并添加循环内的赋值不会有任何收益。

赋值运算符

[编辑 | 编辑源代码]

在赋值运算符重载(operator=)中,如果您确定它永远不会抛出异常,请复制每个成员变量,而不是使用 _复制和交换_ 惯用法。

复制对象的最高效方法是模仿复制构造函数的适当初始化列表,也就是说,首先调用基类的类似成员函数,然后按声明顺序复制每个成员变量。

不幸的是,这种技术不是 _异常安全的_,也就是说,如果在此操作期间抛出了异常,一些已构造的子对象的析构函数可能永远不会被调用。因此,如果在复制过程中有可能会抛出异常,您必须使用一种 _异常安全_ 的技术,尽管它不会具有最佳性能。

最优雅的 _异常安全_ 赋值技术是称为 _复制和交换_ 的技术。它由以下代码示例,其中 `C` 表示类的名称,而 `C` 是要定义的成员函数

C& C::operator=(C new_value) {
    swap(new_value);
    return *this;
}

重载以避免转换

[编辑 | 编辑源代码]

为了避免代价高昂的转换,请为最常见的参数类型定义重载函数。

假设您编写了以下函数

int f(const std::string& s) { return s[0]; }

其目的是允许编写以下代码

std::string s("abc");
int n = f(s);

但它也可以被以下代码使用

int n = f(string("abc"));

并且,由于从 `char*` 到 `std::string` 的隐式转换,它也可以被以下代码使用

int n = f("abc");

最后两个对 `f` 函数的调用效率都很低,因为它们创建了一个临时的非空 `std::string` 对象。

为了保持第一个示例调用的效率,您必须定义以下函数重载

int f(const char* s) { return s[0]; }

一般来说,如果一个函数在调用时传递了一个意外类型但可以隐式转换为预期类型的参数,则会创建一个预期类型的临时对象。

为了避免这种临时对象,您必须定义一个原始函数的重载,它接受实际传递的对象类型的参数,从而避免了转换的需要。

华夏公益教科书