You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

替换std::unique_ptr.reset为std::make_unique后程序性能骤降50%?

Why std::make_unique<char[]> Slowed Down Your Tests by 50%

Let's break down what's happening here—this is a classic case of subtle initialization behavior catching developers off guard.

First, let's recap your code snippets for clarity:

Old (Fast) C++11 Code

class Foo { 
public: 
    Foo(size_t size) { array.reset(new char[size]); } 
private: 
    std::unique_ptr<char[]> array; 
};

New (Slow) C++14 Code

class Foo { 
public: 
    Foo(size_t size) { array = std::make_unique<char[]>(size); } 
private: 
    std::unique_ptr<char[]> array; 
};

The Root Cause: Default Initialization vs Value Initialization

The key difference between these two implementations boils down to how allocated memory is initialized:

  • When you use new char[size], this triggers default initialization for POD types like char. For arrays, this means memory is allocated but left in its raw, uninitialized state (whatever garbage data was on the heap stays there).
  • std::make_unique<char[]>(size) instead performs value initialization. For char arrays, this translates to every single byte being set to \0 (null character).

If your size is large (say, megabytes of data per allocation), that zero-initialization step adds massive, unnecessary overhead—exactly the kind of thing that can cut your test suite speed in half.

How to Verify This Theory

You can confirm the issue by manually replicating make_unique's behavior:

// This is exactly what std::make_unique<char[]>(size) does under the hood
array.reset(new char[size]());

If this runs just as slow as your new code, you've confirmed zero-initialization is the culprit.

Fixes for the Performance Hit

Option 1: Use C++20's std::make_unique_for_overwrite

If you can upgrade to C++20, this is the cleanest solution. std::make_unique_for_overwrite is explicitly designed to skip initialization, matching the behavior of your original new char[size]:

array = std::make_unique_for_overwrite<char[]>(size);

Option 2: Stick with reset(new...) (C++11/14/17)

If C++20 isn't an option, there's no shame in keeping your original reset(new char[size]) pattern. It's safe here (no memory leak risk since you're immediately assigning to a unique_ptr) and avoids the zero-initialization cost entirely.

Option 3: Roll Your Own Helper (C++14/17)

If you want the safety of a make_unique-style function without the initialization overhead, create a tiny wrapper:

template<typename T>
std::unique_ptr<T> make_unique_uninitialized(size_t count) {
    static_assert(std::is_array_v<T>, "This helper is only for array types");
    using ElementType = std::remove_extent_t<T>;
    return std::unique_ptr<T>(new ElementType[count]);
}

// Usage:
array = make_unique_uninitialized<char[]>(size);

A Quick Best Practice Note

While std::make_unique is generally recommended (it prevents certain edge-case memory leaks), its default value-initialization isn't always necessary. Always ask: do you actually need the array to start as all \0s?

  • If you're going to overwrite the array immediately with your own data, zero-initialization is wasted work.
  • If you do need the array to be zeroed, keep using make_unique—the performance hit is unavoidable (and probably necessary).

内容的提问来源于stack exchange,提问作者user363778

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:35:41