C++ vector 避免 fill 0
我们在profiler的时候有的时候发现memset占用热点比较高。而且是std::vector::resize 带来的。这个明显是没必要的, 例如:
std::vector<int> result;
// 这里resize会 fill 0
result.resize(input_rows);
for(int i = 0;i < input_rows; ++i) {
result[i] = transfer(input[i]);
}
如何消除这个呢:
allocator利用 new T;
#include <memory>
#include <array>
#include <new> // for std::construct_at
// 假设我们有一个元素类型为 T,大小为 N 的 std::array
template<typename T, std::size_t N>
std::unique_ptr<std::array<T, N>> make_array_for_overwrite() {
// 分配未初始化内存
auto raw_ptr = new T[N];
// 使用 std::unique_ptr 管理内存,避免内存泄漏
auto deleter = [](T* ptr) {
delete[] ptr;
};
std::unique_ptr<std::array<T, N>, decltype(deleter)> array_ptr(reinterpret_cast<std::array<T, N>*>(raw_ptr), deleter);
return array_ptr;
}
// 使用示例
int main() {
auto my_array_ptr = make_array_for_overwrite<int, 10>();
// 现在 my_array_ptr 指向一个未初始化的 std::array<int, 10>
// 在使用前必须逐个元素进行初始化
for (int& element : *my_array_ptr) {
std::construct_at(&element);
}
// 使用 my_array_ptr...
}
或者可以利用自定义allocator
template <typename T, size_t trailing = 16, typename A = std::allocator<T>>
class RawAllocator : public A {
static_assert(std::is_trivially_destructible_v<T>, "not trivially destructible type");
typedef std::allocator_traits<A> a_t;
public:
template <typename U>
struct rebind {
using other = RawAllocator<U, trailing, typename a_t::template rebind_alloc<U>>;
};
using A::A;
// allocate more than caller required
T* allocate(size_t n) {
T* x = A::allocate(n + RawAllocator::_trailing);
return x;
}
// deallocate the storage referenced by the pointer p
void deallocate(T* p, size_t n) { A::deallocate(p, (n + RawAllocator::_trailing)); }
// do not initialized allocated.
// 注意这里是 new (placed) U 而不是 new (placed) U();
template <typename U>
void construct(U* ptr) noexcept(std::is_nothrow_default_constructible<U>::value) {
::new (static_cast<void*>(ptr)) U;
}
template <typename U, typename... Args>
void construct(U* ptr, Args&&... args) {
a_t::construct(static_cast<A&>(*this), ptr, std::forward<Args>(args)...);
}
private:
static const size_t _trailing = trailing;
};