【发布时间】:2018-09-23 21:42:21
【问题描述】:
我最近开始使用 C++14 而不是 C++11 对我的 C++ 代码库进行现代化改造。
在用 C++14 中的 std::make_unique 替换单个出现的 std::unique_ptr.reset(new ...) 后,我意识到我的测试套件(由大约 30 个 C++ 测试程序组成)运行速度慢了大约 50%。
旧的 C++11 代码(快速):
class Foo
{
public:
Foo(size_t size)
{
array.reset(new char[size]);
}
private:
std::unique_ptr<char[]> array;
};
新的 C++14 代码(慢):
class Foo
{
public:
Foo(size_t size)
{
array = std::make_unique<char[]>(size);
}
private:
std::unique_ptr<char[]> array;
};
使用带有std::make_unique 的 C++14 代码时,GCC 和 Clang 的运行速度要慢得多。当我使用 valgrind 测试两个版本时,它报告 C++11 和 C++14 代码使用相同数量的分配和相同数量的分配内存,并且没有内存泄漏。
当我查看上面生成的测试程序程序集时,我怀疑使用 std::make_unique 的 C++14 版本会在使用 memset 分配后重置内存。 C++11版本不这样做:
C++11 程序集(GCC 7.4、x64)
main:
sub rsp, 8
movsx rdi, edi
call operator new[](unsigned long)
mov rdi, rax
call operator delete[](void*)
xor eax, eax
add rsp, 8
ret
C++14 程序集(GCC 7.4、x64)
main:
push rbx
movsx rbx, edi
mov rdi, rbx
call operator new[](unsigned long)
mov rcx, rax
mov rax, rbx
sub rax, 1
js .L2
lea rax, [rbx-2]
mov edx, 1
mov rdi, rcx
cmp rax, -1
cmovge rdx, rbx
xor esi, esi
call memset
mov rcx, rax
.L2:
mov rdi, rcx
call operator delete[](void*)
xor eax, eax
pop rbx
ret
问题:
初始化内存是std::make_unique 的已知功能吗?如果不是,还有什么可以解释我遇到的性能下降?
【问题讨论】:
-
这确实看起来像是“我不喜欢这个,我为什么要为此付出代价”的情况......
-
@Richard Compiler Explorer 即使使用 -O3 也会重现该问题。您的示例未显示此问题,因为您的大小已硬编码为 10。
-
std::make_unique 问题的编译器浏览器链接:godbolt.org/g/7URbfP