std::array
被认为是零成本抽象,这意味着编译器应该可以对其进行相当优化。
对于任何零成本抽象,它可能会导致小的编译时间损失,如果不支持真正零成本所需的优化,那么它可能会导致小规模或运行时损失。
但是,请注意编译器可以自由地在结构的末尾添加填充。由于std::array
是一个结构,你应该检查你的平台是如何处理的std::array
,但我非常怀疑你的情况。
拿这个数组和std::array
案例:
#include <numeric>
#include <iterator>
template<std::size_t n>
int stuff(const int(&arr)[n]) {
return std::accumulate(std::begin(arr), std::end(arr), 0);
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6};
return stuff(arr);
}
#include <numeric>
#include <iterator>
#include <array>
template<std::size_t n>
int stuff(const std::array<int, n>& arr) {
return std::accumulate(std::begin(arr), std::end(arr), 0);
}
int main() {
std::array arr = {1, 2, 3, 4, 5, 6};
return stuff(arr);
}
Clang 非常支持这种情况。所有带有std::array
或原始数组的情况都以相同的方式处理:
-O2
/-O3
数组和std::array
铿锵声:
main: # @main
mov eax, 21
ret
std::array
但是,对于原始数组情况,GCC 似乎在优化它时遇到了问题:
-O3
使用 GCC 进行数组和std::array
:
main:
movdqa xmm0, XMMWORD PTR .LC0[rip]
movaps XMMWORD PTR [rsp-40], xmm0
mov edx, DWORD PTR [rsp-32]
mov eax, DWORD PTR [rsp-28]
lea eax, [rdx+14+rax]
ret
.LC0:
.long 1
.long 2
.long 3
.long 4
-O2
然后,在原始数组的情况下,它似乎可以更好地优化并失败std::array
:
-O2
海湾合作委员会std::array
:
main:
movabs rax, 8589934593
lea rdx, [rsp-40]
mov ecx, 1
mov QWORD PTR [rsp-40], rax
movabs rax, 17179869187
mov QWORD PTR [rsp-32], rax
movabs rax, 25769803781
lea rsi, [rdx+24]
mov QWORD PTR [rsp-24], rax
xor eax, eax
jmp .L3
.L5:
mov ecx, DWORD PTR [rdx]
.L3:
add rdx, 4
add eax, ecx
cmp rdx, rsi
jne .L5
rep ret
-O2
GCC原始数组:
main:
mov eax, 21
ret
似乎 GCC 错误未能优化-O3
但成功-O2
在最新版本中已修复。
这是一个编译器资源管理器,其中包含O2
所有O3
std::array
说明所有这些情况后,您可以看到一个常见模式:二进制文件中没有输出任何有关 的信息。没有构造函数,没有operator[]
,甚至没有迭代器,也没有算法。一切都是内联的。编译器擅长内联简单的函数。std::array
成员函数通常非常非常简单。
如果您创建 std::array< SomeObject, 5 > 的另一个实例,然后调用该 std::array 的函数,那么这些函数中的每一个现在是否会在二进制文件中复制,从而占用更多闪存?X 字节内存 + Y 字节内存。
好吧,您更改了数组包含的数据类型。如果您手动添加所有函数的重载来处理这种额外的情况,那么是的,所有这些新函数可能会占用一些空间。如果你的函数很小,它们很有可能被内联并占用更少的空间。正如您在上面的示例中看到的那样,内联和常量折叠可能会大大减少您的二进制大小。
在上面的示例中,如果您创建了第二个 std::array 实例,对函数的调用是否也会复制闪存中的函数调用?即使两个实例属于同一类型,int?
再次取决于。如果您有许多以数组大小为模板的函数,则std::array
原始数组和原始数组都可能“创建”不同的函数。但同样,如果它们是内联的,则无需担心重复。
两者都是原始数组std::array
,您可以传递指向数组开头的指针并传递大小。如果您发现这更适合您的情况,请使用它,但仍然是原始数组并且std::array
可以做到这一点。对于原始数组,它隐式衰减为指针,并且std::array
您必须使用arr.data()
来获取指针。