std::ranges::uninitialized_default_construct
De cppreference.com
<tbody>
</tbody>
| Definido en el archivo de encabezado <memory>
|
||
| Signatura de la llamada |
||
template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S> requires std::default_initializable<std::iter_value_t<I>> I uninitialized_default_construct( I first, S last ); |
(1) | (desde C++20) |
template <no-throw-forward-range R> requires std::default_initializable<ranges::range_value_t<R>> ranges::borrowed_iterator_t<R> uninitialized_default_construct( R&& r ); |
(2) | (desde C++20) |
1) Construye objetos de tipo
std::iter_value_t<I> en el almacenamiento no inicializado designado por el rango [first, last) por la inicialización por defecto, como si fuera por
for (; first != last; ++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.
2) Igual que (1), pero usa
r como rango, como si se usara ranges::begin(r) como first, y ranges::end(r) como last.Las entidades similares a funciones descritas en esta página son niebloids, es decir:
- Las listas de argumentos de plantilla explícitas no se pueden especificar al llamar a cualquiera de ellas.
- Ninguna de ellas es visible para la búsqueda dependiente de argumentos.
- Cuando alguna de ellas se encuentra mediante la búsqueda normal no calificada como el nombre a la izquierda del operador de llamada a función, se inhibe la búsqueda dependiente de argumentos.
En la práctica, pueden implementarse como objetos función o con extensiones de compilador especiales.
Parámetros
| first, last | - | Par iterador-centinela que denota el rango de los elementos a inicializar. |
| r | - | El rango de elementos a inicializar. |
Valor de retorno
Un iterador igual a last.
Complejidad
Lineal en la distancia entre first y last.
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_fn {
template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S>
requires std::default_initializable<std::iter_value_t<I>>
I operator()( I first, S last ) 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, last); // skip initialization
I rollback {first};
try {
for (; !(first == last); ++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;
}
}
template <no-throw-forward-range R>
requires std::default_initializable<ranges::range_value_t<R>>
ranges::borrowed_iterator_t<R>
operator()( R&& r ) const {
return (*this)(ranges::begin(r), ranges::end(r));
}
};
inline constexpr uninitialized_default_construct_fn uninitialized_default_construct{};
|
Ejemplo
Ejecuta este código
#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 {first + n};
std::ranges::uninitialized_default_construct(first, last);
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
// generalmente no llena con ceros el área de memoria no inicializada dada.
constexpr char etalon[] { 'A', 'B', 'C', 'D', '\n' };
char v[] { 'A', 'B', 'C', 'D', '\n' };
std::ranges::uninitialized_default_construct(std::begin(v), std::end(v));
if (std::memcmp(v, etalon, sizeof(v)) == 0) {
std::cout << " ";
// Tal vez comportamiento no definido, pendiente CWG 1997:
// for (const char c : v) { std::cout << c << ' '; }
for (const char c : etalon) { std::cout << c << ' '; }
} else {
std::cout << "Unspecified\n";
}
}
Posible salida:
1 ▄▀▄▀▄▀▄▀
2 ▄▀▄▀▄▀▄▀
3 ▄▀▄▀▄▀▄▀
4 ▄▀▄▀▄▀▄▀
A B C D
Véase también
(niebloid) | |
| Construye objetos mediante la inicialización de un valor en un área de memoria sin inicializar, definido por un rango. (niebloid) | |
| Construye objetos mediante la inicialización de un valor en un área de memoria sin inicializar, definido por un inicio y una cuenta. (niebloid) | |
| Construye objetos mediante la inicialización por defecto en un área de memoria sin inicializar, definido por un rango. (plantilla de función) |