2010-02-28 9 views
7

Acabo de ver this nice puntero copy-on-write implementación. Se ve bastante genérico y útil, así que mi pregunta es: ¿Esta clase está contenida en alguno de los kits de herramientas de C++ (boost, loki, etc.)? Si no, realmente me gustaría saber por qué, porque es una expresión realmente útil y aparentemente una implementación genérica parece factible (como aquella a la que me he vinculado).¿Por qué no hay impulso :: copy_on_write_ptr?

+3

Está contenido en el kit de herramientas Qt, y se llama 'QSharedDataPointer'. Es bastante agradable. –

Respuesta

6

Hubo un gran debate sobre la posibilidad, y al menos una versión sugerida de lo que eventualmente salió como auto_ptr fue para un puntero COW de referencia contada.

Desafortunadamente, la hora de COW ha pasado en su mayoría. Hacer un puntero COW (o COW-whatever) thread-safe puede introducir graves performance problems.

Editar: Volviendo a leer eso, me siento obligado a señalar que no todos los uso de COW necesariamente obsoletos. Hay momentos en que todavía tiene sentido. La sobrecarga de un incremento seguro de subprocesos es bastante fija, por lo que solo es cuestión de qué tan grande debe ser un objeto o qué tan caro es copiarlo, para que COW tenga sentido. También hay momentos/lugares en los que tiene lotes de copias de un objeto (no modificado), y los ahorros en la memoria pueden ser una compensación razonable: los ahorros en memoria justifican un tiempo de procesador adicional. Si puede guardar un escaneado de datos en/desde el disco, puede salir adelante con prisa.

+0

Eso me pone triste. :( – Frank

+0

@Frank: ¿triste? ¿Cómo? No suele conducir a un código más rápido, ¿por qué usarlo? – jalf

2

Como Jerry Coffin dijo que se ha demostrado que el lenguaje COW introdujo problemas de rendimiento ... pero en realidad hay otro problema.

No es posible (como se demuestra en el mismo artículo al que se vincula) escribir realmente una implementación genérica de COW. En la implementación COW de std::string, la Copia se realiza siempre que se invoca una operación que realmente modificará el estado de la cadena. Sin embargo, ¿cómo se supone que un puntero lo sabe? No tiene conocimiento sobre la clase a la que apunta.

Por ejemplo, vamos a suponer que hago esto:

void method(Foo& foo, flag_t flag) 
{ 
    if (flag == flag::Yes) foo.modify(); 
} 

void invoke(COWPointer<Foo> ptr) 
{ 
    method(*ptr, flag::No); 
} 

Oups! Realizo una copia del objeto Foo aunque no se vaya a modificar.

El problema es que si bien esta clase VACA ayuda, en realidad se ha de envolver:

class Foo 
{ 
public: 

private: 
    COWPointer<FooImpl> mImpl; 
}; 

Y entonces los métodos de Foo que realmente modifica el objeto será responsable de copiar el estado FooImpl. Tan seguro que la clase ayuda, pero tampoco es una bala de plata.

Y todo este problema ... sin estar seguro de ganar realmente el rendimiento debido a los problemas de sincronización en una aplicación de MT ...

¿No es más fácil de evitar el copiado de hecho siempre que sea posible (usando referencias/punteros) en lugar de ajustar tu clase para una posible ganancia en algunas situaciones que penalizará a los usuarios que ya se ocuparon de problemas de rendimiento?

0

Existe una contradicción entre "puntero" y "copiar al escribir": por definición, desreferenciar un puntero no lo cambia, y cambiar *p no cambia p.

Por lo tanto, un puntero const se puede desreferenciar, y el lvalue resultante puede ser modificable.

Realmente está hablando de un contenedor de un elemento, no de un puntero.

Cuestiones relacionadas