std::ranges::uninitialized_move_n, std::ranges::uninitialized_move_n_result
| Definido en el archivo de encabezado <memory>
|
||
| Signatura de la llamada |
||
template <std::input_iterator I, no-throw-forward-iterator O, no-throw-sentinel-for<O> S> requires std::constructible_from<std::iter_value_t<O>, std::iter_rvalue_reference_t<I>> uninitialized_move_n_result<I, O> uninitialized_move_n( I ifirst, std::iter_difference_t<I> n, O ofirst, S olast ); |
(1) | (desde C++20) |
| Tipos auxiliares |
||
template<class I, class O> using uninitialized_move_n_result = ranges::in_out_result<I, O>; |
(2) | (desde C++20) |
Mueve N elementos del rango de entrada que comienza en ifirst al almacenamiento no inicializado designado por el rango [ofirst, olast), donde N es min(n, ranges::distance(ofirst, olast)).
El efecto es equivalente a:
for (; n-- > 0 && ofirst != olast; ++ifirst, ++ofirst)
::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first))))
std::remove_reference_t<std::iter_reference_t<O>>(ranges::iter_move(ifirst));
Si se lanza una excepción durante la inicialización, los objetos que ya se construyeron en [ofirst, olast) se destruyen en un orden no especificado. Asimismo, los objetos en el rango de entrada que comienza en ifirst, que ya fueron movidos, quedan en un estado válido pero no especificado.
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
| ifirst | - | El comienzo del rango de entrada de elementos a ser movidos. |
| ofirst, olast | - | Par iterador-centinela que denota el rango de salida de los elementos a inicializar. |
| n | - | El número de elementos a mover. |
Valor de retorno
{ifirst + N, ofirst + 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 mejorar la eficiencia de ranges::uninitialized_move_n, p.ej., mediante el uso de ranges::copy_n, si el tipo valor del rango de salida es TrivialType.
Posible implementación
struct uninitialized_move_n_fn {
template <std::input_iterator I, no-throw-forward-iterator O,
no-throw-sentinel-for<O> S>
requires std::constructible_from<std::iter_value_t<O>,
std::iter_rvalue_reference_t<I>>
ranges::uninitialized_move_n_result<I, O>
operator()( I ifirst, std::iter_difference_t<I> n, O ofirst, S olast ) const {
O current {ofirst};
try {
for (; n-- > 0 && current != olast; ++ifirst, ++current)
::new (const_cast<void*>(static_cast<const volatile void*>
(std::addressof(*current)))) std::remove_reference_t<
std::iter_reference_t<O>>(ranges::iter_move(ifirst));
return {std::move(ifirst), std::move(current)};
} catch (...) { // rollback: destruir los elementos construidos
for (; ofirst != current; ++ofirst)
ranges::destroy_at(std::addressof(*ofirst));
throw;
}
}
};
inline constexpr uninitialized_move_n_fn uninitialized_move_n{};
|
Ejemplo
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>
void print(auto rem, auto first, auto last) {
for (std::cout << rem; first != last; ++first)
std::cout << std::quoted(*first) << ' ';
std::cout << '\n';
}
int main() {
std::string in[] { "No", "se requiere", "diagnóstico", };
print("inicialmente, in es: ", std::begin(in), std::end(in));
if (
constexpr auto sz = std::size(in);
void* out = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz)
) {
try {
auto first {static_cast<std::string*>(out)};
auto last {first + sz};
std::ranges::uninitialized_move_n(std::begin(in), sz, first, last);
print("antes del movimiento, in es: ", std::begin(in), std::end(in));
print("después del movimiento, out es: ", first, last);
std::ranges::destroy(first, last);
}
catch (...) {
std::cout << "¡Excepción!\n";
}
std::free(out);
}
}
Posible salida:
inicialmente, in es: "No" "se requiere" "diagnóstico"
antes del movimiento, in es: "" "" ""
después del movimiento, out es: "No" "se requiere" "diagnóstico"
Véase también
(C++20) |
Mueve un rango de objetos a un área de memoria sin inicializar. (niebloid) |
(C++17) |
Mueve un número de objetos a un área de memoria sin inicializar. (niebloid) |