shared_ptr - Rendimiento del puntero inteligente C++
smart pointer c++ (6)
¿Cuánto cuesta más el uso de punteros inteligentes, en particular boost :: shared_ptr, en comparación con los indicadores simples en términos de tiempo y memoria? ¿El uso de punteros descubiertos es mejor para las partes de alto desempeño de los sistemas embebidos / integrados? ¿Recomendaría usar punteros simples o punteros inteligentes para componentes de rendimiento intensivo?
Boost proporciona diferentes punteros inteligentes. En general, tanto la ocupación de la memoria, que varía de acuerdo con el tipo de puntero inteligente, y el rendimiento no deberían ser un problema. Para una comparación de rendimiento puede consultar este http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/smarttests.htm .
Como puede ver, solo se tienen en cuenta la construcción, la copia y la destrucción para la comparación del rendimiento, lo que significa que eliminar la referencia de un puntero inteligente tiene supuestamente el mismo costo que el de un puntero sin formato.
El siguiente fragmento de código demuestra que no hay pérdida de rendimiento al usar un shared_ptr<>
en lugar de un puntero sin formato:
#include <iostream>
#include <tr1/memory>
int main()
{
#ifdef USE_SHARED_PTR
std::tr1::shared_ptr<volatile int> i(new int(1));
#else
volatile int * i = new int(1);
#endif
long long int h = 0;
for(long long int j=0;j < 10000000000LL; j++)
{
h += *i;
}
std::cout << h << std::endl;
return 0;
}
La última vez que probé, con VC6, el compilador no pudo optimizar el código con un puntero inteligente tan bien como podría hacerlo con un puntero sin formato. Las cosas podrían haber cambiado desde entonces.
Los punteros inteligentes contados por referencia (el tipo más común) solo cuestan más cuando los copia, los crea y los elimina. Este costo adicional puede ser sustancial si está copiando mucho, porque la mayoría de ellos son seguros para subprocesos.
Si solo desea un puntero de "autodeleción", existe el auto_ptr muy difamado, o el nuevo y brillante (pero no mucho soporte aún) unique_ptr de C ++ 0x.
La única forma de lidiar con los problemas de rendimiento es perfilar su código. La mayor parte de los problemas de rendimiento se imagina de todos modos; solo el perfil le indicará dónde se encuentran sus cuellos de botella.
Si resulta que el uso de punteros inteligentes produce un cuello de botella donde los punteros crudos no funcionan, ¡utilice punteros crudos! Hasta entonces, no me preocuparía demasiado por eso; la mayoría de las operaciones en punteros inteligentes son razonablemente rápidas. Probablemente compares cadenas demasiado a menudo (o algo así) para que importen.
Desreferenciar los punteros inteligentes es típicamente trivial, sin duda para mejorar en el modo de lanzamiento. Todos los controles de impulso están en tiempo de compilación. (Los punteros inteligentes podrían, en teoría, hacer cosas inteligentes en los hilos). Esto aún deja muchas otras operaciones. Nicola mencionó construcción, copia y destrucción. Este no es el conjunto completo, sin embargo. Otras operaciones importantes son el intercambio, la asignación y el restablecimiento a NULL. Básicamente, cualquier operación que requiera inteligencia.
Tenga en cuenta que algunas de estas operaciones están excluidas por algunos punteros inteligentes. Por ejemplo, boost::scoped_ptr
ni siquiera se puede copiar, y menos aún asignar. Como esto deja menos operaciones, la implementación se puede optimizar para estos pocos métodos.
De hecho, con la próxima TR1, es bastante probable que los compiladores obtengan mejores resultados con los punteros inteligentes que con los punteros sin procesar. Por ejemplo, es posible que un compilador demuestre que un puntero inteligente que no se puede copiar no tiene alias en algunas situaciones, simplemente porque no se puede copiar. Piénselo: el aliasing ocurre cuando se crean dos punteros apuntando al mismo objeto. Si no se puede copiar el primer puntero, ¿cómo un segundo puntero apunta hacia el mismo objeto? (Hay formas de evitarlo también, el operador * debe devolver un valor l)
Hay una casa intermedia a menudo pasada por alto entre un std::vector<T*>
administrado "manualmente" std::vector<T*>
(es decir, punteros crudos) y un std::vector<boost::shared_ptr<T> >
, en forma de boost::ptr_container
clases boost::ptr_container
.
Estos combinan el rendimiento de un contenedor de puntero sin formato con la comodidad de un contenedor de punteros inteligentes (es decir, proporcionan la funcionalidad que a las personas les gustaría que proporcionaran los contenedores STL de std::auto_ptr
, si eso funcionaba ).