smart - unique pointer c++
Preguntas sobre usos de shared_ptr-C++ (5)
- Sí, la copia es absolutamente barata. Además de mantener el puntero, hay (generalmente) otro miembro de datos para la clase shared_ptr: el recuento de uso.
- No puedo responder esto, generalmente uso las versiones boost antes de que se introdujera make_shared (1.40?)
- Use boost :: const_pointer_cast
- shared_ptr tiene el operador == /! = definido. En su ejemplo anterior: si (f)
Tengo algunas preguntas sobre las mejores prácticas de uso de shared_ptr
.
Pregunta 1
¿Copiar shared_ptr
barato? ¿O necesito pasarlo como referencia a mis propias funciones de ayuda y devolver como valor? Algo como,
void init_fields(boost::shared_ptr<foo>& /*p_foo*/);
void init_other_fields(boost::shared_ptr<foo>& /*p_foo*/);
boost::shared_ptr<foo> create_foo()
{
boost::shared_ptr<foo> p_foo(new foo);
init_fields(p_foo);
init_other_fields(p_foo);
}
Pregunta 2
¿Debo usar boost::make_shared
para construir un shared_ptr
? En caso afirmativo, ¿qué ventajas ofrece? ¿Y cómo podemos usar make_shared
cuando T
no tiene un constructor sin parámetros?
Pregunta 3
¿Cómo usar const foo*
? He encontrado dos enfoques para hacer esto.
void take_const_foo(const foo* pfoo)
{
}
int main()
{
boost::shared_ptr<foo> pfoo(new foo);
take_const_foo(pfoo.get());
return 0;
}
O
typedef boost::shared_ptr<foo> p_foo;
typedef const boost::shared_ptr<const foo> const_p_foo;
void take_const_foo(const_p_foo pfoo)
{
}
int main()
{
boost::shared_ptr<foo> pfoo(new foo);
take_const_foo(pfoo);
return 0;
}
Pregunta 4
¿Cómo puedo devolver y verificar NULL
en un objeto shared_ptr
? Es algo como
boost::shared_ptr<foo> get_foo()
{
boost::shared_ptr<foo> null_foo;
return null_foo;
}
int main()
{
boost::shared_ptr<foo> f = get_foo();
if(f == NULL)
{
/* .. */
}
return 0;
}
Cualquier ayuda sería genial.
- Una de las razones básicas para la existencia de shared_ptr es ser relativamente barato de copiar.
- Hay versiones de make_shared que toman parámetros (y si su compilador soporta plantillas variadas, una que toma una lista de parámetros variables).
- ¿Suena como si estuvieras buscando const_ptr_cast?
- Para devolver un puntero nulo, puede pasar ''0'' al ctor share_ptr. Para comprobar si hay un puntero nulo, puede comparar p.get () con 0.
Copiar un shared_ptr ahora cuesta 32 bytes en la copia de la pila y los incrementos / decrementos adicionales de refcount. Decida si es barato para usted o no, pero no veo ninguna razón para no pasar una referencia constante, especialmente que ya tiene un typedef para ptr:
void f(const foo_ptr &myfoo)
especialmente dado que el estándar no-write- El parámetro de permisos que pasa en C ++ es una referencia constante.Preferiría no tener funciones que acepten punteros que no se compartan. Esto es similar (aunque no idéntico) a la semántica de paso de parámetros en Java y C #. ¿Por qué sumergirse en decidir cada vez cómo pasar un objeto, en lugar de tener una forma estándar de hacerlo?
Utilice
if(p)
al igual que para los punteros regulares. La semántica de conversión booleana es bastante clara.
La copia es barata, el puntero no ocupa mucho espacio. El objetivo principal era hacer que fuera pequeño para permitir el uso en contenedores por valor (por ejemplo,
std::vector< shared_ptr<Foo> >
).make_shared
toma una cantidad variable de parámetros, y es el mecanismo preferido para construirlo usted mismo (comomake_pair
). La ventaja es la legibilidad, especialmente si se trata de pasar temporarios y / o espacios de nombres:boost::const_ptr_cast como ya se sugirió
Los punteros inteligentes tienen operadores sobrecargados y se pueden usar directamente en expresiones evaluadas a bool. No utilice
get
. Por nada. En lugar de compararp.get
con cualquier cosa, compare una instancia de puntero vacía (my_ptr != boost::shared_ptr< MyClass >()
)
AD.2
func_shared( boost::shared_ptr<my_tools::MyLongNamedClass>(
new my_tools::MyLongNamedClass( param1, param2 ) );
versus
func_shared( boost::make_shared<my_tools::MyLongNamedClass>( param1, param2 ));
La mayoría de las preguntas fueron respondidas, pero no estoy de acuerdo con que una copia de shared_ptr sea barata.
Una copia tiene una semántica diferente de una de paso por referencia. Se modificará el recuento de referencia, lo que activará un incremento atómico en el mejor de los casos y un bloqueo en el peor de los casos. Debe decidir qué semántica necesita y luego sabrá si debe pasar por referencia o por valor.
Desde el punto de vista del rendimiento, generalmente es una mejor idea utilizar un contenedor de punteros de impulso en lugar de un contenedor de shared_ptr.