c++17:至少必须替换哪些版本的全局运算符 new/delete 才能涵盖所有情况?
c++17: which versions of global operators new/delete must be replaced at least to cover all cases?
当全局重载运算符 new 和 delete 时,需要实现哪些版本以覆盖所有情况?
似乎在 c++17 之前实现 void* operator new(size_t bytes)
和 void operator delete(void* ptr)
就足够了,因为默认实现的数组版本和非抛出版本是使用这两个函数实现的。
但是c++17呢?例如 https://en.cppreference.com/w/cpp/memory/new/operator_new 没有提到 (4) 将通过调用 (3) 来实现(而提到 (2) 是通过调用 (1) 来实现)。
那么,在 c++17 中,需要让对 new 和 delete 版本的所有调用(除了具有本地覆盖的 类)被替换覆盖的最少运算符是多少?
来自 cppreference https://en.cppreference.com/w/cpp/memory/new/operator_new#Global_replacements (And a similar note with operator delete
):
The standard library implementations of the nothrow versions (5-8) directly calls the corresponding throwing versions (1-4). The standard library implementation of the throwing array versions (2,4) directly calls the corresponding single-object version (1,3). Thus, replacing the throwing single object allocation functions is sufficient to handle all allocations.
所以你需要替换这些函数:
void* operator new(std::size_t count);
void* operator new(std::size_t count, std::align_val_t al);
void operator delete(void* ptr) noexcept;
void operator delete(void* ptr, std::align_val_t al) noexcept;
其余的将根据这四个来实施。
如果您没有对齐的 malloc-equivalent 来替换对齐的版本,这里是根据 [=26] 对齐的 new
/delete
的简单实现=]版本:
#include <cstddef>
#include <new>
#include <memory>
void* operator new(std::size_t count, std::align_val_t al) {
std::size_t align = static_cast<std::size_t>(al);
if (align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__) [[unlikely]] return operator new(count);
std::size_t actually_allocating = align + count;
if (actually_allocating < count || (actually_allocating += sizeof(void*)) < (align + count)) [[unlikely]] {
// overflow
throw std::bad_alloc();
}
void* unaligned = operator new(actually_allocating);
void* aligned = unaligned;
std::align(align, 0, aligned, actually_allocating);
// Store a pointer to the start of the aligned memory, to be retrieved by delete
::new (static_cast<void*>(static_cast<char*>(aligned) - sizeof(void*))) void*(unaligned);
return aligned;
}
void operator delete(void* ptr, std::align_val_t al) noexcept {
if (static_cast<std::size_t>(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) [[likely]] {
ptr = *static_cast<void**>(static_cast<void*>(static_cast<char*>(ptr) - sizeof(void*)));
}
operator delete(ptr);
}
当全局重载运算符 new 和 delete 时,需要实现哪些版本以覆盖所有情况?
似乎在 c++17 之前实现 void* operator new(size_t bytes)
和 void operator delete(void* ptr)
就足够了,因为默认实现的数组版本和非抛出版本是使用这两个函数实现的。
但是c++17呢?例如 https://en.cppreference.com/w/cpp/memory/new/operator_new 没有提到 (4) 将通过调用 (3) 来实现(而提到 (2) 是通过调用 (1) 来实现)。
那么,在 c++17 中,需要让对 new 和 delete 版本的所有调用(除了具有本地覆盖的 类)被替换覆盖的最少运算符是多少?
来自 cppreference https://en.cppreference.com/w/cpp/memory/new/operator_new#Global_replacements (And a similar note with operator delete
):
The standard library implementations of the nothrow versions (5-8) directly calls the corresponding throwing versions (1-4). The standard library implementation of the throwing array versions (2,4) directly calls the corresponding single-object version (1,3). Thus, replacing the throwing single object allocation functions is sufficient to handle all allocations.
所以你需要替换这些函数:
void* operator new(std::size_t count);
void* operator new(std::size_t count, std::align_val_t al);
void operator delete(void* ptr) noexcept;
void operator delete(void* ptr, std::align_val_t al) noexcept;
其余的将根据这四个来实施。
如果您没有对齐的 malloc-equivalent 来替换对齐的版本,这里是根据 [=26] 对齐的 new
/delete
的简单实现=]版本:
#include <cstddef>
#include <new>
#include <memory>
void* operator new(std::size_t count, std::align_val_t al) {
std::size_t align = static_cast<std::size_t>(al);
if (align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__) [[unlikely]] return operator new(count);
std::size_t actually_allocating = align + count;
if (actually_allocating < count || (actually_allocating += sizeof(void*)) < (align + count)) [[unlikely]] {
// overflow
throw std::bad_alloc();
}
void* unaligned = operator new(actually_allocating);
void* aligned = unaligned;
std::align(align, 0, aligned, actually_allocating);
// Store a pointer to the start of the aligned memory, to be retrieved by delete
::new (static_cast<void*>(static_cast<char*>(aligned) - sizeof(void*))) void*(unaligned);
return aligned;
}
void operator delete(void* ptr, std::align_val_t al) noexcept {
if (static_cast<std::size_t>(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) [[likely]] {
ptr = *static_cast<void**>(static_cast<void*>(static_cast<char*>(ptr) - sizeof(void*)));
}
operator delete(ptr);
}