c ++ – Implementation of static_vector using an array of std :: aligned_storage, with std :: launder and forwarding

I'm trying to develop the static_vector implementation on the std :: align_storage reference page, but I'd like to split it into two parts. First, an aligned_storage_array that supports the perfect transfer (so I can place it) and does not require a default constructor, and then the static_vector infrastructure that builds it. This will allow me to use aligned_storage alignment for other static data structures that I plan to create in the future.

aligné_storage_array.h

#pragma once

#understand 
#understand 
#understand 
#understand 

namespace nonstd
{
model
    struct aligned_storage_ray
{
public:
aligned_storage_array () = default;
~ align_storage_array () = default;

aligned_storage_array (aligned_storage_array && rhs)
// requires std :: is_move_constructible_v
            = default;

aligned_storage_array & operator = (aligned_storage_array && rhs)
// requires std :: is_move_assignable_v
            = default;

aligned_storage_array (const aligned_storage_array & rhs)
// requires std :: is_copy_constructible_v
            = default;

aligned_storage_array & operator = (const aligned_storage_array & rhs)
// requires std :: is_copy_assignable_v
            = default;

// Cut
constexpr std :: size_t size () const noexcept {return N; }
constexpr std :: size_t max_size () const noexcept {return N; }

// Access
T & operator online[](std :: size_t pos)
{
returns * std :: launder (
réinterpréter_cast(
std :: addressof (m_data[pos])));
}

online operator[](std :: size_t pos) const
{
returns * std :: launder (
réinterpréter_cast(
std :: addressof (m_data[pos])));
}

inline T & at (std :: size_t pos)
{
returns * std :: launder (
réinterpréter_cast(
std :: addressof (m_data.at (pos))));
}

inline const T & at (std :: size_t pos) const
{
returns * std :: launder (
réinterpréter_cast(
std :: addressof (m_data.at (pos))));
}

// operations
model
        online use (size_t pos, Args && ... args)
{
return
* :: new (std :: addressof (m_data[pos]))
T (std :: forward(args) ...);
}

model
        inline T & bounded_place (size_t pos, args && ... args)
{
return
* :: new (std :: addressof (m_data.at (pos)))
T (std :: forward(args) ...);
}

destroy the void online (std :: size_t pos)
{
std :: destroy_at (
std :: launder (
réinterpréter_cast(
std :: addressof (m_data[pos]))));
}

Inline void bounded_destroy (std :: size_t pos)
{
std :: destroy_at (
std :: launder (
réinterpréter_cast(
std :: addressof (m_data.at (pos)))));
}

private:
std :: array <std :: aligned_storage_t, N> m_data;
};
}

static_vector.h

#pragma once

#understand 
#understand 

#include "aligned_storage_array.h"

namespace nonstd
{
model
    struct static_vector
{
public:
using value_type = T;
using the pointer = T *;
using const_pointer = const T *;
using reference = type_value &;
using const_reference = const value_type &;
using iterator = type_value *;
using const_iterator = const value_type *;
using size_type = std :: size_t;

static_vector () = default;
~ static_vector () {destroy_n (m_size); }

static_vector (static_vector && rhs) = default;
static_vector & operator = (static_vector && rhs) = default;
static_vector (const static_vector & rhs) = default;
static_vector & operator = (const static_vector & rhs) = default;

// size and capacity
constexpr std :: size_t size () const {return m_size; }
constexpr std :: size_t max_size () const {return N; }
constexpr bool empty () const {return m_size == 0; }

// iterators
iterator online begin () {return & m_data[0]; }
In_Connect_iterator inline begin () const {return & m_data[0]; }
online iterator end () {return & m_data[m_size]; }
inline const_iterator end () const {return & m_data[m_size]; }

// Access
T & operator online[](std :: size_t pos)
{
returns m_data[pos];
}

online operator[](std :: size_t pos) const
{
returns m_data[pos];
}

inline T & at (std :: size_t pos)
{
if (pos> = m_size)
throws std :: out_of_range ("static vector index out of range");
returns m_data.at (pos);
}

inline const T & at (std :: size_t pos) const
{
if (pos> = m_size)
throws std :: out_of_range ("static vector index out of range");
returns m_data.at (pos);
}

// operations
model
        inline T & emplace_back (Args && ... args)
{
T & result = m_data.bounded_emplace (m_size, args ...);
++ m_size;
return the result;
}

inline void clear ()
{
std :: size_t count = m_size;
m_size = 0; // in case of exception
destroy_n (count);
}

private:
cancel destroy_n (std :: size_t count)
{
for (std :: size_t pos = 0; pos <count; ++ pos)
m_data.destroy (pos);
}

rangé_storage_array m_data;
std :: size_t m_size = 0;
};
}

A complete functional test configuration is available here (wandbox). Concept lines can be uncommented and analyzed in a compiler that supports them. I would especially like additional eyes to determine:

  1. Is Actually sure for the new placement with respect to alignment?
  2. Is the use of std :: launder correct?
  3. Is the use of reinterpret_cast correct (or should it rather be static_casts?)
  4. Are there hidden pitfalls that I should monitor here (aside from maximum capacity)?
  5. Am I paranoid enough (:: new, std :: address_of, std :: destroy_at)? Any other security features that I can set up to handle risky overloads for the operator?
  6. How should I handle copying and moving? Aligné_storage will be happy to copy, whether or not T has copy and move functions. I do not think these concepts are sufficient because I do not call the manufacturers or the operators. However, in the base of the table, I do not know which entries are and can not be copied / moved.

I'm told that it looks like something like boost :: small_vector, but I want to generalize aligned_storage_array because I want to use it later for a number of different static structures. In addition, I would like to know more about alignment / placement, transfer and money laundering.

Thank you!