Estoy interesado en construir un contenedor uninitialized_vector
, que será semánticamente idéntico a std::vector
con la advertencia de que los nuevos elementos que de otro modo se crearían con un constructor sin argumentos se crearán en su lugar sin inicialización Principalmente estoy interesado en evitar inicializar POD a 0.
Hasta donde puedo decir, no hay forma de lograr esto combinando
Evitar la construcción predeterminada de elementos en contenedores estándarstd::vector
con un tipo especial de asignador.
me gustaría construir mi contenedor en la misma línea que std::stack
, que se adapta un recipiente proporcionado por el usuario (en mi caso, std::vector
). En otras palabras, me gustaría evitar volver a implementar la totalidad de std::vector
y en su lugar proporcionar una "fachada" a su alrededor.
¿Existe una manera simple de controlar la construcción predeterminada desde el "exterior" de std::vector
?
Aquí está la solución llegué a, que se inspiró la respuesta de kerrek:
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <cassert>
// uninitialized_allocator adapts a given base allocator
// uninitialized_allocator's behavior is equivalent to the base
// except for its no-argument construct function, which is a no-op
template<typename T, typename BaseAllocator = std::allocator<T>>
struct uninitialized_allocator
: BaseAllocator::template rebind<T>::other
{
typedef typename BaseAllocator::template rebind<T>::other super_t;
template<typename U>
struct rebind
{
typedef uninitialized_allocator<U, BaseAllocator> other;
};
// XXX for testing purposes
typename super_t::pointer allocate(typename super_t::size_type n)
{
auto result = super_t::allocate(n);
// fill result with 13 so we can check afterwards that
// the result was not default-constructed
std::fill(result, result + n, 13);
return result;
}
// catch default-construction
void construct(T *p)
{
// no-op
}
// forward everything else with at least one argument to the base
template<typename Arg1, typename... Args>
void construct(T* p, Arg1 &&arg1, Args&&... args)
{
super_t::construct(p, std::forward<Arg1>(arg1), std::forward<Args>(args)...);
}
};
namespace std
{
// XXX specialize allocator_traits
// this shouldn't be necessary, but clang++ 2.7 + libc++ has trouble
// recognizing that uninitialized_allocator<T> has a well-formed
// construct function
template<typename T>
struct allocator_traits<uninitialized_allocator<T> >
: std::allocator_traits<std::allocator<T>>
{
typedef uninitialized_allocator<T> allocator_type;
// for testing purposes, forward allocate through
static typename allocator_type::pointer allocate(allocator_type &a, typename allocator_type::size_type n)
{
return a.allocate(n);
}
template<typename... Args>
static void construct(allocator_type &a, T* ptr, Args&&... args)
{
a.construct(ptr, std::forward<Args>(args)...);
};
};
}
// uninitialized_vector is implemented by adapting an allocator and
// inheriting from std::vector
// a template alias would be another possiblity
// XXX does not compile with clang++ 2.9
//template<typename T, typename BaseAllocator>
//using uninitialized_vector = std::vector<T, uninitialized_allocator<T,BaseAllocator>>;
template<typename T, typename BaseAllocator = std::allocator<T>>
struct uninitialized_vector
: std::vector<T, uninitialized_allocator<T,BaseAllocator>>
{};
int main()
{
uninitialized_vector<int> vec;
vec.resize(10);
// everything should be 13
assert(std::count(vec.begin(), vec.end(), 13) == vec.size());
// copy construction should be preserved
vec.push_back(7);
assert(7 == vec.back());
return 0;
}
Esta solución funcionará dependiendo de cómo de cerca compilador & std::vector
aplicación de STL de un proveedor en particular se ajusta a C++ 11.
¿Puedes simplemente definir un constructor predeterminado que no haga nada? Apuesto a que el compilador puede incluir u omitirlo esp con la optimización activada. –
@Doug T.- Eso puede resolver el caso del constructor predeterminado, pero las cosas interesantes parecen suceder en '' 'resize''' - no está claro cómo llamar a funciones como' '' resize''' sin invocar constructores. –
@Doug: Tiene la advertencia de que ya no eres POD con un constructor definido por el usuario ... –