Evitar la construcción predeterminada de elementos en contenedores estándar

Estoy interesado en construir unauninitialized_vector container, que será semánticamente idéntico astd::vector con la advertencia de que los nuevos elementos que de otro modo se crearían con un constructor sin argumentos se crearán sin inicialización. Estoy principalmente interesado en evitar inicializar POD a 0. Por lo que puedo decir, no hay forma de lograr esto combinandostd::vector con un tipo especial de asignador.

Me gustaría construir mi contenedor en la misma línea questd::stack, que adapta un contenedor proporcionado por el usuario (en mi caso,std::vector). En otras palabras, me gustaría evitar volver a implementar la totalidad destd::vector y en su lugar proporcione una "fachada" a su alrededor.

Hay una manera simple de controlar la construcción predeterminada desde el "exterior" destd::vector?

Aquí está la solución a la que llegué, que 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;
}

sta solución funcionará dependiendo de qué tan cerca esté el compilador de un proveedor en particular y el STL destd::vector implementación se ajusta a c ++ 11.

Respuestas a la pregunta(3)

Su respuesta a la pregunta