c++ - tecnicas - sistema de recomendacion python
std:: vector, construcción por defecto, C++ 11 y cambios de rotura (2)
Hoy corrí contra un tema bastante sutil sobre el que me gustaría opinar.
Considere la siguiente clase de lenguaje compartido de cuerpo compartido:
struct S
{
S() : p_impl(new impl) {}
private:
struct impl;
boost::shared_ptr<impl> p_impl;
};
La diversión aparece cuando tratas de ponerlos en vectores de la siguiente manera:
std::vector<S> v(42);
Ahora, con MSVC 8 como mínimo, 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());
...
};
Bajo las escenas, solo un objeto S
se construye por defecto, los n
elementos del vector
se copian de él.
Ahora, con C ++ 11, hay referencias rvalue. Entonces no puede funcionar así. Si un vector
se construye como
std::vector<S> v(42);
entonces lo más probable es que las implementaciones elijan construir de forma predeterminada los n
objetos dentro del vector, ya que la construcción de copias puede no estar disponible. Esto sería un cambio radical en este caso.
Mi pregunta es:
- ¿El estándar C ++ 03 exige que
std::vector
debe tener un constructor definido como anteriormente, es decir. con un argumento predeterminado? En particular, ¿hay alguna garantía de que las entradas del objeto vector se copien en lugar de construirse por defecto? - ¿Qué dice el estándar C ++ 11 sobre este mismo punto?
- Veo esto como una posibilidad para un cambio de ruptura entre C ++ 03 y C + 11. ¿Este problema ha sido investigado? Resuelto?
PD: por favor, no hay comentarios sobre el constructor predeterminado de la clase S
arriba. Fue esto o implementar alguna forma de construcción perezosa.
¿El estándar C ++ 03 exige que
std::vector
debe tener un constructor definido como el anterior, es decir, con un argumento predeterminado? En particular, ¿hay alguna garantía de que las entradas del objeto vector 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 que contenga n
elementos que sean 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 predeterminado para x
, se ha agregado (2) . Este valor de constructor inicializa n
elementos en el contenedor. No se hacen copias.
Si necesita el comportamiento anterior, puede asegurarse de que (1) se invoque proporcionando un segundo argumento a la invocación del constructor:
std::vector<S> v(42, S());
Veo esto como una posibilidad para un cambio de ruptura entre C ++ 03 y C ++ 11. Veo esto como una posibilidad para un cambio de ruptura entre C ++ 03 y C ++ 11. ¿Este problema ha sido investigado? Resuelto?
Sí, como demuestra su ejemplo, este es un cambio radical.
Como no soy miembro del comité de normalización de C ++ (y no he prestado especial atención a los documentos relacionados con la biblioteca en los correos), no sé en qué medida se discutió este cambio radical.
Creo que la solución para el caso de uso que describió no es óptima y no está completa, es por eso que tuvo problemas para actualizarse a C ++ 11.
C ++ siempre se preocupa por la semántica y cuando escribe un programa en c ++, será mejor que comprenda su semántica. Entonces, en su caso, desea crear N objetos, pero mientras no los modifique, desea que compartan la misma memoria para la optimización. Buena idea, pero cómo hacer esto: 1) copiar el constructor. 2) implementación estática + constructor de copia. ¿Has considerado ambas soluciones?
Considere que necesita M vectores de N objetos, ¿cuántas veces se asignará la memoria compartida si elige el primer escenario? Es M, pero ¿por qué tenemos que asignar M de memoria si queremos crear vectores que contengan objetos MxN?
Entonces, la implementación correcta aquí es apuntar a la memoria estática de forma predeterminada, y asignar memoria solo si se cambia el objeto. En tal caso, la asignación de vectores M de N objetos le dará ... 1 asignación de memoria "compartida".
En su caso, ha violado el constructor de copia de abuso de semántica correcto, que es: 1) no obvio 2) no es óptimo y ahora tiene que pagar.