std:: vector, construcción predeterminada, C++11 y cambios de ruptura


He corrido hoy contra un tema bastante sutil sobre el que me gustaría tener su opinión.

Considere la siguiente clase de expresión de cuerpo compartido de variedad de jardín:

struct S
{
    S() : p_impl(new impl) {}
private:
    struct impl;
    boost::shared_ptr<impl> p_impl;
};

La diversión aparece cuando intentas ponerlos en vectores de la siguiente manera:{[15]]}

std::vector<S> v(42);

Ahora, con MSVC 8 al menos, todos los elementos en v comparten el mismo miembro impl. En realidad, lo que causa esto es el constructor vector:

template <typename T, typename A = ...>
class vector
{
    vector(size_t n, const T& x = T(), const A& a = A());
    ...
};

Debajo de las escenas, solo un objeto S se construye por defecto, los elementos n del vector se copian de él.

Ahora, con C++11, hay referencias rvalue. Así que no puede funcionar así. Si a vector se construye como

std::vector<S> v(42);

Entonces lo más probable es que las implementaciones opten por construir por defecto los objetos n dentro del vector, ya que la construcción de copia puede no estar disponible. Esto sería un cambio decisivo en este caso.

Mi pregunta es:

  1. ¿Exige el estándar C++03 que std::vector debe tener un constructor definido como arriba, ie. ¿con un argumento predeterminado ? En particular, ¿hay una garantía de que las entradas del objeto vectorial se copien en lugar de construirse por defecto ?
  2. ¿Qué dice el estándar C++11 sobre este mismo punto ?
  3. Veo esto como una posibilidad de un cambio de ruptura entre C++03 y C+11. ¿Se ha investigado este asunto ? Resuelto ?

PD: Por favor, no hay comentarios sobre el constructor predeterminado de la clase S anterior. Era esto o implementando alguna forma de construcción perezosa.

Author: Xeo, 2011-04-22

2 answers

¿El estándar C++03 exige que std::vector tenga un constructor definido como el anterior, es decir, con un argumento predeterminado? En particular, ¿hay una garantía de que las entradas del objeto vectorial se copien en lugar de construirse por defecto?

Sí, el comportamiento especificado es que x se copia n veces para que el contenedor se inicialice para contener con n elementos que son todas copias de x.


¿Qué dice el estándar C++11 sobre este mismo punto?

En C++11 este constructor se ha convertido en dos constructores.

vector(size_type n, const T& x, const Allocator& = Allocator()); // (1)
explicit vector(size_type n);                                    // (2)

Excepto por el hecho de que ya no tiene un argumento predeterminado para el segundo parámetro, (1) funciona de la misma manera que en C++03: x se copia n veces.

En lugar del argumento por defecto para x, (2) se ha añadido. Este valor del constructor-inicializa los elementos n en el contenedor. No se hacen copias.

Si usted requiere el viejo comportamiento, usted puede asegurarse de que (1) se llama proporcionando un segundo argumento a la invocación del constructor:

std::vector<S> v(42, S());

Veo esto como una posibilidad de un cambio radical entre C++03 y C++11. Veo esto como una posibilidad de un cambio radical entre C++03 y C++11. ¿Se ha investigado este asunto? Resuelto?

Sí, como su ejemplo demuestra, esto es de hecho un cambio decisivo.

Ya que no soy miembro de el comité de estandarización de C++ (y no he prestado especial atención a los documentos relacionados con la biblioteca en los correos), no se hasta qué punto se discutió este cambio radical.

 46
Author: James McNellis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-09 02:59:45

Creo que la solución para el caso de uso que describiste no es óptima y no está completa, por eso tienes problemas para actualizar a C++11.

C++ siempre se preocupa por la semántica y cuando escribes un programa en c++ es mejor que entiendas tu semántica. Así que en su caso desea crear N objetos, pero mientras no los está cambiando desea que compartan la misma memoria para la optimización. Buena idea, pero ¿cómo hacer esto: 1) constructor de copia. 2) implementación estática + constructor de copia. ¿Tienes considerado ambas soluciones?

Considere que necesita M vectores de N objetos, ¿cuántas veces se asignará memoria compartida si elige 1er escenario? Es M, pero ¿por qué necesitamos asignar memoria M veces si queremos crear vectores que contengan objetos MxN?

Así que la implementación correcta aquí es apuntar a la memoria estática por defecto, y asignar memoria solo si se cambia el objeto. En tal caso la asignación de M vectores de N objetos le dará... 1 asignación de memoria 'compartida'.

En su caso usted violó el correcto abuso semántico copy constructor, que es: 1) no es obvio 2) no óptimo y ahora tienes que pagar.

 -3
Author: Alexey Sergeev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-01 22:42:39