HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

static_new and static_delete

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
static_newstatic_deleteand

Problem

Here's a trick for preallocating some memory for some type T. Do there exist similar tricks? Improvements?

```
#include

#include

#include

#include

#include

#include

#include

namespace
{
template
struct static_store
{
static constexpr auto const max_instances =
::std::numeric_limits::digits * sizeof(A);

static void cleanup() { delete [] store_; }

#ifdef __GNUC__
template
static int ffz(U const v)
{
return __builtin_ctzll(~v);
}
#elif _MSC_VER && !__INTEL_COMPILER
template
static int ffz(U const v)
{
return ::std::numeric_limits::digits * sizeof(v) -
__lzcnt64(v & -v);
}
#elif __INTEL_COMPILER
template
static int ffz(U const v)
{
return _bit_scan_forward(~v);
}
#else
template
static int ffz(U v)
{
decltype(ffz()) b{};

for (; (v & 1); ++b)
{
v >>= 1;
}

return b;
}
#endif

static ::std::atomic_flag lock_;

static A memory_map_;

static typename ::std::aligned_storage::type* store_;
};

template
::std::atomic_flag static_store::lock_;

template
A static_store::memory_map_;

template
typename ::std::aligned_storage::type*
static_store::store_{(::std::atexit(static_store::cleanup),
new typename ::std::aligned_storage::type[static_store::max_instances])};

template
inline T* static_new(A&& ...args)
{
using static_store = static_store;

while (static_store::lock_.test_and_set(::std::memory_order_acquire))
{
::std::this_thread::yield();
}

auto const i(static_store::ffz(static_store::memory_map_));

auto p(new (&static_store::store_[i]) T(::std::forward(args)...));

static_store::memory_map_ |= 1ull
inline void static_delete(T* const p)
{
using static_store = static_store;

auto const i(p - static_cast(static_cast(
static_store::store_)));
//assert(!as_const(static_store::memory_map_)[i]);

while (st

Solution

I still have trouble understanding how the whole works, but there are still some small things that could be improved:

-
In your comments, you say that A is an integer type used as a bitmask. The safest bitmask types are unsigned types or std::bitset. You should make this condition clear in your code, write

template 
  struct static_store { /* ... */ };


You could even make it an error to use a nonconforming type and create a is_bitmask trait, which would allow you to create a meaningful error message:

static_assert(is_bitmask::value,
              "the BitmaskType requirements are not satisfied");


-
I got confused with these lines:

template 
inline T* static_new(A&& ...args)


It is once again a naming problem: I had in mind the template parameter A from static_store. Since it represents arguments to be forwarding, you should just use the common convetion and name it Args instead. I don't know whether there are written guidelines to name variadic parameter packs, but Args is probably the name that I saw the most often.

-
You could probably slightly hide details and reduce the visual burden by using a typedef for the type of store_:

using store_type = typename ::std::aligned_storage::type;

Code Snippets

template <typename T, typename BitmaskType=unsigned>
  struct static_store { /* ... */ };
static_assert(is_bitmask<BitmaskType>::value,
              "the BitmaskType requirements are not satisfied");
template <typename T, typename ...A>
inline T* static_new(A&& ...args)
using store_type = typename ::std::aligned_storage<sizeof(T), alignof(T)>::type;

Context

StackExchange Code Review Q#31319, answer score: 8

Revisions (0)

No revisions yet.