Espacios de nombres
Variantes
Acciones

std::ranges::uninitialized_default_construct_n

De cppreference.com
< cpp‎ | memory
 
 
Biblioteca de servicios
 
Gestión de memoria dinámica
Punteros inteligentes
(C++11)
(C++11)
(C++11)
(hasta C++17)
(C++11)
(C++23)
Asignadores de memoria
Recursos de memoria
Almacenamiento no inicializado
Algoritmos de memoria no inicializada
Algoritmos restringidos de memoria no inicializada
Apoyo para recolección de basura
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
Misceláneos
(C++20)
(C++11)
(C++11)
 
Definido en el archivo de encabezado <memory>
Signatura de la llamada
template <no-throw-forward-iterator I>

requires std::default_initializable<std::iter_value_t<I>>

I uninitialized_default_construct_n( I first, std::iter_difference_t<I> n );
(desde C++20)

Construye n objetos de tipo std::iter_value_t<I> en el área de memoria no inicializada que comienza en first por la inicialización por defecto, como si fuera por

for (; n-- > 0; ++first)
  ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first))))
      std::remove_reference_t<std::iter_reference_t<I>>;

Si se lanza una excepción durante la inicialización, los objetos ya construidos se destruyen en un orden no especificado.

Las entidades similares a funciones descritas en esta página son niebloids, es decir:

En la práctica, pueden implementarse como objetos función o con extensiones de compilador especiales.

Contenido

Parámetros

first - El comienzo del rango de elementos a inicializar.
n - El número de elementos a construir.

Valor de retorno

El fin del rango de objetos (es decir, ranges::next(first, n)).

Complejidad

Lineal en n.

Excepciones

La excepción lanzada en la construcción de los elementos en el rango de destino, si existe.

Notas

Una implementación puede omitir la construcción de objetos (sin cambiar el efecto observable) si no se llama a un constructor por defecto no trivial mientras se inicializa por defecto un objeto std::iter_value_t<I>, que puede ser detectado por std::is_trivially_default_constructible_v.

Posible implementación

struct uninitialized_default_construct_n_fn {
    template <no-throw-forward-iterator I>
    requires std::default_initializable<std::iter_value_t<I>>
    I operator()( I first, std::iter_difference_t<I> n ) const {
        using ValueType = std::remove_reference_t<std::iter_reference_t<I>>;
        if constexpr (std::is_trivially_default_constructible_v<ValueType>)
            return ranges::next(first, n); // omitir la inicialización
        I rollback {first};
        try {
            for (; n-- > 0; ++first)
                ::new (const_cast<void*>(static_cast<const volatile void*>
                        (std::addressof(*first)))) ValueType;
            return first;
        } catch (...) { // rollback: destruir los elementos construidos
            for (; rollback != first; ++rollback)
                ranges::destroy_at(std::addressof(*rollback));
            throw;
        }
    }
};
 
inline constexpr uninitialized_default_construct_n_fn uninitialized_default_construct_n{};

Ejemplo

#include <cstring>
#include <iostream>
#include <memory>
#include <string>
 
int main()
{
    struct S { std::string m{ "█▓▒░ █▓▒░ " }; };
 
    constexpr int n {4};
    alignas(alignof(S)) char out[n * sizeof(S)];
 
    try
    {
        auto first {reinterpret_cast<S*>(out)};
        auto last = std::ranges::uninitialized_default_construct_n(first, n);
 
        auto count {1};
        for (auto it {first}; it != last; ++it) {
            std::cout << count++ << ' ' << it->m << '\n';
        }
 
        std::ranges::destroy(first, last);
    }
    catch(...) { std::cout << "¡Excepción!\n"; }
 
    // Observa que para "tipos triviales" uninitialized_default_construct_n
    // generalmente no llena con ceros el área de memoria no inicializada dada.
    constexpr int etalon[] { 1, 2, 3, 4, 5, 6 };
    int v[] { 1, 2, 3, 4, 5, 6 };
    std::ranges::uninitialized_default_construct_n(std::begin(v), std::size(v));
    if (std::memcmp(v, etalon, sizeof(v)) == 0) {
        // Tal vez comportamiento no definido, pendiente CWG 1997:
        // for (const int i : v) { std::cout << i << ' '; }
        for (const int i : etalon) { std::cout << i << ' '; }
    } else {
        std::cout << "Unspecified!";
    }
    std::cout << '\n';
}

Posible salida:

1 █▓▒░ █▓▒░
2 █▓▒░ █▓▒░
3 █▓▒░ █▓▒░
4 █▓▒░ █▓▒░
1 2 3 4 5 6

Véase también

Construye objetos mediante la

inicialización por defecto en un área de memoria sin inicializar, definido por un rango.
(niebloid) [editar]

Construye objetos mediante la inicialización de un valor en un área de memoria sin inicializar, definido por un rango.
(niebloid) [editar]
Construye objetos mediante la inicialización de un valor en un área de memoria sin inicializar, definido por un inicio y una cuenta.
(niebloid) [editar]
Construye objetos mediante la inicialización por defecto en un área de memoria sin inicializar, definido por un inicio y una cuenta.
(plantilla de función) [editar]