使用 std::array 与数组传递对象数组
Passing object array with std::array vs array
今天我正在和我的朋友们讨论在 C++ 中传递对象数组的正确方法。这两者在效率上有什么区别吗:
Struct Apple {
std::string color;
}
void colors(Apple A[]) {
A[0].color = "red";
}
int main() {
Appple apples[10];
colors(apples);
return 0;
}
.
Struct Apple {
std::string color;
}
void colors(std::array<Apple, 10>& A) {
A[0].color = "red";
}
int main() {
std::array<Apple, 10> apples;
colors(apples);
return 0;
}
Performance-wise,这取决于你数组的大小,你的编译器和使用的编译选项。基准.
当你传递一个常规数组时,它基本上会衰减为一个指针,所以你只有传递一个指针的开销。如果传递 std::array
by-copy,则需要复制整个数组。如果你通过引用传递它,那么你就有传递引用的开销(这通常与传递指针相同)。
为了类型安全,我仍然强烈建议您使用 std::array
。
Performance-wise,没有。它们都只是在内存地址周围改组,所以性能是一样的。
Style-wise,我总是推荐 std::array
而不是 C 数组。 C 数组仅在 C++ 中用于与旧代码的向后兼容。新东西具有遵循标准容器 class 接口的优点,因此可以与 <algorithm>
和其他库中所有奇特的 STL 通用方法一起使用。它还知道自己的规模,这本身就是一个很大的胜利。
您正在陷入 C 和 C++ 的初学者常见错误 -- 您不能将数组作为参数传递给函数。语言不允许。如果您声明一个以数组作为参数的函数,编译器会(悄悄地)为您将其更改为指针,因为数组可以隐式转换为指针(在大多数地方通常是这样)。
所以你的第一个例子真的是:
void colors(Apple *A) {
A[0].color = "red";
}
现在很明显你的问题是:传递指针和传递引用在性能上有什么区别吗?
否 -- 引用和指针的实现方式相同 -- 作为地址 -- 因此它们之间的性能没有差异。
这两个函数在 x86_64
上使用 GCC 7.3
生成相同的代码。
此处:https://godbolt.org/g/aguVfF
第一个例子:
void colors(Apple A[]) {
A[0].color = 12;
}
_Z6colorsP5Apple:
mov DWORD PTR [rdi], 12
ret
第二个例子:
void colors(std::array<Apple, 10>& A) {
A[0].color = 13;
}
_Z6colorsRSt5arrayI5AppleLm10EE:
mov DWORD PTR [rdi], 13
ret
传递内置数组时,它们衰减为指向其第一个元素的指针。此外,当对象通过通常使用指针实现的引用传递时。
因为 std::array
是一个 非常薄的 内置数组包装器,它的地址很可能与其第一个元素的地址相同。编译器的优化器可以看穿它。
您不太可能找到使用 std::array
比内置数组慢的示例,因为 std::array
基本上是包裹在 中的内置数组零成本 语法糖利用编译时信息,内置版本没有(如数组的大小)。
今天我正在和我的朋友们讨论在 C++ 中传递对象数组的正确方法。这两者在效率上有什么区别吗:
Struct Apple {
std::string color;
}
void colors(Apple A[]) {
A[0].color = "red";
}
int main() {
Appple apples[10];
colors(apples);
return 0;
}
.
Struct Apple {
std::string color;
}
void colors(std::array<Apple, 10>& A) {
A[0].color = "red";
}
int main() {
std::array<Apple, 10> apples;
colors(apples);
return 0;
}
Performance-wise,这取决于你数组的大小,你的编译器和使用的编译选项。基准.
当你传递一个常规数组时,它基本上会衰减为一个指针,所以你只有传递一个指针的开销。如果传递 std::array
by-copy,则需要复制整个数组。如果你通过引用传递它,那么你就有传递引用的开销(这通常与传递指针相同)。
为了类型安全,我仍然强烈建议您使用 std::array
。
Performance-wise,没有。它们都只是在内存地址周围改组,所以性能是一样的。
Style-wise,我总是推荐 std::array
而不是 C 数组。 C 数组仅在 C++ 中用于与旧代码的向后兼容。新东西具有遵循标准容器 class 接口的优点,因此可以与 <algorithm>
和其他库中所有奇特的 STL 通用方法一起使用。它还知道自己的规模,这本身就是一个很大的胜利。
您正在陷入 C 和 C++ 的初学者常见错误 -- 您不能将数组作为参数传递给函数。语言不允许。如果您声明一个以数组作为参数的函数,编译器会(悄悄地)为您将其更改为指针,因为数组可以隐式转换为指针(在大多数地方通常是这样)。
所以你的第一个例子真的是:
void colors(Apple *A) {
A[0].color = "red";
}
现在很明显你的问题是:传递指针和传递引用在性能上有什么区别吗?
否 -- 引用和指针的实现方式相同 -- 作为地址 -- 因此它们之间的性能没有差异。
这两个函数在 x86_64
上使用 GCC 7.3
生成相同的代码。
此处:https://godbolt.org/g/aguVfF
第一个例子:
void colors(Apple A[]) {
A[0].color = 12;
}
_Z6colorsP5Apple:
mov DWORD PTR [rdi], 12
ret
第二个例子:
void colors(std::array<Apple, 10>& A) {
A[0].color = 13;
}
_Z6colorsRSt5arrayI5AppleLm10EE:
mov DWORD PTR [rdi], 13
ret
传递内置数组时,它们衰减为指向其第一个元素的指针。此外,当对象通过通常使用指针实现的引用传递时。
因为 std::array
是一个 非常薄的 内置数组包装器,它的地址很可能与其第一个元素的地址相同。编译器的优化器可以看穿它。
您不太可能找到使用 std::array
比内置数组慢的示例,因为 std::array
基本上是包裹在 中的内置数组零成本 语法糖利用编译时信息,内置版本没有(如数组的大小)。