在可能的情况下使用std的construct_at/destroy_at

This commit is contained in:
mutouyun 2022-02-27 18:30:42 +08:00
parent c54e052838
commit 21f34bd99c
2 changed files with 50 additions and 0 deletions

View File

@ -9,15 +9,27 @@
#include <new> // placement-new #include <new> // placement-new
#include <type_traits> // std::enable_if_t #include <type_traits> // std::enable_if_t
#include <utility> // std::forward #include <utility> // std::forward
#include <memory> // std::construct_at, std::destroy_at, std::addressof
#include <cstddef>
#include "libipc/def.h" #include "libipc/def.h"
#include "libipc/detect_plat.h"
LIBIPC_NAMESPACE_BEG_ LIBIPC_NAMESPACE_BEG_
/**
* @brief Creates an object at a given address, like 'construct_at' in c++20
* @see https://en.cppreference.com/w/cpp/memory/construct_at
*/
template <typename T, typename... A> template <typename T, typename... A>
auto construct(void *p, A &&... args) auto construct(void *p, A &&... args)
-> std::enable_if_t<::std::is_constructible<T, A...>::value, T *> { -> std::enable_if_t<::std::is_constructible<T, A...>::value, T *> {
#if defined(LIBIPC_CPP_20)
return std::construct_at(static_cast<T *>(p), std::forward<A>(args)...);
#else
return ::new (p) T(std::forward<A>(args)...); return ::new (p) T(std::forward<A>(args)...);
#endif
} }
template <typename T, typename... A> template <typename T, typename... A>
@ -26,9 +38,30 @@ auto construct(void *p, A &&... args)
return ::new (p) T{std::forward<A>(args)...}; return ::new (p) T{std::forward<A>(args)...};
} }
/**
* @brief Destroys an object at a given address, like 'destroy_at' in c++17
* @see https://en.cppreference.com/w/cpp/memory/destroy_at
*/
template <typename T> template <typename T>
void *destroy(T *p) noexcept { void *destroy(T *p) noexcept {
#if defined(LIBIPC_CPP_17)
std::destroy_at(p);
#else
p->~T(); p->~T();
#endif
return p;
}
template <typename T, std::size_t N>
void *destroy(T (*p)[N]) noexcept {
#if defined(LIBIPC_CPP_20)
std::destroy_at(p);
#elif defined(LIBIPC_CPP_17)
std::destroy(std::begin(*p), std::end(*p));
#else
for (auto &elem : *p) destroy(std::addressof(elem));
#endif
return p; return p;
} }

View File

@ -18,16 +18,33 @@ TEST(utility, construct) {
EXPECT_EQ(pfoo->a_, 123); EXPECT_EQ(pfoo->a_, 123);
EXPECT_EQ(pfoo->b_, 321); EXPECT_EQ(pfoo->b_, 321);
EXPECT_EQ(pfoo->c_, '1'); EXPECT_EQ(pfoo->c_, '1');
ipc::destroy(pfoo);
struct Bar : Foo { struct Bar : Foo {
Bar(int a, short b, char c) Bar(int a, short b, char c)
: Foo{a, b, c} {} : Foo{a, b, c} {}
~Bar() { a_ = 0; }
}; };
std::aligned_storage_t<sizeof(Bar)> bar; std::aligned_storage_t<sizeof(Bar)> bar;
Bar *pbar = ipc::construct<Bar>(&bar, 123, short(321), '1'); Bar *pbar = ipc::construct<Bar>(&bar, 123, short(321), '1');
EXPECT_EQ(pbar->a_, 123); EXPECT_EQ(pbar->a_, 123);
EXPECT_EQ(pbar->b_, 321); EXPECT_EQ(pbar->b_, 321);
EXPECT_EQ(pbar->c_, '1'); EXPECT_EQ(pbar->c_, '1');
ipc::destroy(pbar);
EXPECT_EQ(pbar->a_, 0);
std::aligned_storage_t<sizeof(Bar)> bars[3];
for (auto &b : bars) {
auto pb = ipc::construct<Bar>(&b, 321, short(123), '3');
EXPECT_EQ(pb->a_, 321);
EXPECT_EQ(pb->b_, 123);
EXPECT_EQ(pb->c_, '3');
}
ipc::destroy(reinterpret_cast<Bar(*)[3]>(&bars));
for (auto &b : bars) {
auto pb = reinterpret_cast<Bar *>(&b);
EXPECT_EQ(pb->a_, 0);
}
} }
namespace { namespace {