'`make_unique_for_overwrite` still initializes `std::pair` elements
I was hoping that
auto myPairs = make_unique_for_overwrite<pair<uint64_t, void*>[]>(arraySize);
would give me uninitialized memory for my pair
s. I am overwriting those later anyway and the (unnecessary) initialization is currently responsible for 120ms out of 600ms overall runtime for my algorithm.
What is the most idiomatic way to avoid this initialization?
Solution 1:[1]
According to cppreference, the default constructor of std::pair
always value-initializes (aka zeroes) its elements.
The solution is to get rid of pair
. You can replace it with a structure with two members.
I know I could still just allocate ... and then
reinterpret_cast
Attempt to reinterpret_cast
such structure to std::pair
would cause undefined behavior.
Solution 2:[2]
I was hoping that [
make_unique_for_overwrite
] would give me uninitialized memory for my pairs.
It does not. The overload you are calling will allocate memory for an array of std::pair
s, and then default-initialize each element, per https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique:
- Same as (2), except that the array is default-initialized. This overload participates in overload resolution only if T is an array of unknown bound. The function is equivalent to:
unique_ptr<T>(new std::remove_extent_t<T>[size])
So, this call:
auto myPairs = make_unique_for_overwrite<pair<uint64_t, void*>>[]>(arraySize);
Is effectively:
auto myPairs = unique_ptr<pair<uint64_t, void*>[]>(new pair<uint64_t, void*>[arraySize]);
std::pair
's default constructor value-initializes its members, per https://en.cppreference.com/w/cpp/utility/pair/pair:
- Default constructor. Value-initializes both elements of the pair,
first
andsecond
.
- This constructor participates in overload resolution if and only if
std::is_default_constructible_v<first_type>
andstd::is_default_constructible_v<second_type>
are bothtrue
.- This constructor is
explicit
if and only if eitherfirst_type
orsecond_type
is not implicitly default-constructible.
Thus, you are effectively creating an array of pairs that are each initialized to {0, nullptr}
before you even have a change to see the memory.
What is the most idiomatic way to avoid this initialization?
Allocate the raw memory yourself, and then placement-new
the std::pair
elements in it as needed.
Or use std::vector
and let it handle this for you, via its reserve()
method.
Solution 3:[3]
Just do
pair<uint64_t, void*>* myPairs = (pair<uint64_t, void*>*)malloc(sizeof(pair<uint64_t, void*>)*arraySize);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | thedudehimself |