std :: make_unique导致大幅放缓?

时间:2018-04-13 13:47:34

标签: c++ stl g++ c++14 clang++

我最近开始使用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的已知功能?如果没有其他什么可以解释我遇到的性能下降?

1 个答案:

答案 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的类型,它与它的初始化有关。