返回(大)对象时复制开销
Copy overhead when returning (big) objects?
考虑一个简单的Matrix4x4 Identity方法的以下两个实现。
1:这个以 Matrix4x4 引用为参数,其中数据直接写入。
static void CreateIdentity(Matrix4x4& outMatrix) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
outMatrix[i][j] = i == j ? 1 : 0;
}
}
}
2:这个返回一个矩阵4x4,不带任何输入。
static Matrix4x4 CreateIdentity() {
Matrix4x4 outMatrix;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
outMatrix[i][j] = i == j ? 1 : 0;
}
}
return outMatrix;
}
现在,如果我想实际创建一个身份矩阵,我必须做
Matrix4x4 mat;
Matrix4x4::CreateIdentity(mat);
对于第一个变体和
Matrix4x4 mat = Matrix4x4::CreateIdentity();
第二。
第一个显然产生了一个优点,即没有完成一个不必要的副本,同时它不允许将其用作右值;
想象一下Matrix4x4 mat = Matrix4x4::Identity()*Matrix4x4::Translation(5, 7, 6);
最后一个问题:有没有办法尽可能避免使用像Matrix4x4::CreateIdentity();
这样的方法时不必要的副本,同时仍然允许像我上一个代码示例中那样将该方法用作右值?编译器是否自动优化了它?我很困惑如何有效地完成这个(看似(简单的任务。也许我应该实现这两个版本并使用任何合适的版本?
您通常不需要太担心这一点,因为复制省略(在本例中为 NRVO1(是标准的一部分。
更详细一点(危险地(,返回矩阵的版本很可能最终会将其分配给调用函数的堆栈,并且仅在被调用的函数中初始化它,而不调用任何复制构造函数。
因此,除非有什么东西禁止这一点(您可以通过运行它并检查是否调用复制构造函数来发现(,否则您通常不需要担心它。
如果复制省略不能发生(或者只是由于某种原因不会发生,例如,如果编译器不想这样做,因为它不必这样做(,那么你仍然可以确保提供一个移动构造函数,然后使用它代替2。这里的好处是,当您的 return 语句涉及转换为实际返回的类型时,它甚至可以工作。
引用:
-
如果函数按值返回类类型,并且 return 语句的表达式是具有自动存储持续时间的非易失性对象的名称,该对象不是函数参数或 catch 子句参数,并且与函数的返回类型具有相同的类型(忽略顶级 cv-限定(,则省略复制/移动。构造该本地对象时,它直接在存储中构造,否则函数的返回值将被移动或复制到该存储中。这种复制省略的变体称为NRVO,即"命名返回值优化"。
-
如果表达式是左值表达式,并且满足或
将满足复制省略的条件,除了表达式命名函数参数之外,则重载解析以选择要用于初始化返回值的构造函数将执行两次:首先,如果表达式是右值表达式(因此它可以选择移动构造函数或引用 const 的复制构造函数(, 如果没有合适的转换可用,则使用左值表达式第二次执行重载解析(因此它可以选择引用非常量(的复制构造函数(。
即使函数返回类型与表达式类型不同,上述规则也适用(复制省略需要相同的类型(。
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 使用strcpy将char数组的元素复制到另一个数组
- 是否可以初始化不可复制类型的成员变量(或基类)
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 实现无开销push_back的最佳方法是什么
- 复制列表初始化的隐式转换的等级是多少
- 当从函数参数中的临时值调用复制构造函数时
- 有可能在Armadillo中复制MATLAB circshift方法吗
- 复制几乎为空的数组的最快方法
- 以下示例中如何避免代码复制?C++/库达
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 不能将复制初始化与隐式转换的多个步骤一起使用
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 为什么复制而不是移动数据元素?
- char 和 char& 之间是否存在相对复制开销差异?
- 复制开销:双精度与指针
- 返回(大)对象时复制开销