我最近开始使用C ++ 14代替C ++ 11来使我的C ++代码库现代化。
在C ++ 14中用std::unique_ptr.reset(new ...)
替换单个std::make_unique
后,我意识到我的测试套件(包含大约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代码使用相同数量的分配和相同数量的已分配内存,并且没有内存泄漏。
当我查看上面生成的测试程序的程序集时,我怀疑使用memset分配后使用std::make_unique
的C ++ 14版本会重置内存。 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
的已知功能?如果没有其他什么可以解释我遇到的性能下降?
答案 0 :(得分:17)
将内存初始化为
的已知功能std::make_unique
这取决于你所知道的“已知”。但是,这是你的案件之间的区别。 cppreference来自make_unique<T>(size)
来电:
unique_ptr<T>(new typename std::remove_extent<T>::type[size]()) // ~~~~
这就是specified。
new char[size]
分配内存并对其进行默认初始化。 new char[size]()
分配内存并对其进行初始化,在char
的情况下进行零初始化。默认情况下,标准库中的许多内容都将进行值初始化,而不是默认初始化。
同样,make_unique<T>()
执行new T()
而非new T
... make_unique<char>()
会给您0,new char
会为您提供不确定的值。
作为一个类似的例子,如果我希望将vector<char>
调整大小到给定大小的未初始化缓冲区(要立即填充其他内容),我必须使用我自己的分配器或使用一个不是char
的类型,它与它的初始化有关。