2009-03-07 15 views
54

¿Cuál es el equivalente a lo siguiente:Puntero NULL con boost :: shared_ptr?

std::vector<Foo*> vec; 
vec.push_back(NULL); 

cuando se trata de boost::shared_ptr? ¿Es el siguiente código?

std::vector< boost::shared_ptr<Foo> > vec; 
vec.push_back(boost::shared_ptr<Foo>()); 

Nota: puedo rechazar una gran cantidad de tales objetos. ¿Debería declarar un objeto estático global nullPtr en alguna parte? De esta forma, solo uno de ellos debería construirse:

boost::shared_ptr<Foo> nullPtr; 
+4

buenas noticias de la siguiente norma C++: no, puede escribir "vec.emplace_back();" y añada un apuntador nulo :) –

+7

Considere usar 'boost :: ptr_vector' que requiere menos sobrecarga. – Philipp

Respuesta

0

Sí, declarar un puntero nulo global estático.

4

Usted podría declarar un nullPtr global para shared_ptr<Foo>. Pero si contaminas el espacio de nombres global, ¿cómo llamarías al nullPtr global para shared_ptr<Bar>?

Normalmente declaro el ptr nulo como estático en la clase del puntero.

#include <boost\shared_ptr.hpp> 

class Foo; // forward decl 
typedef boost::shared_ptr<Foo> FooPtr; 
class Foo 
{ 
public: 
    static FooPtr Null; 
} 
... 
// define static in cpp file 
FooPtr Foo::Null; 
... 
// use Foo Null 
vec.push_back(Foo::Null); 

De esta forma, cada clase tiene un nulo estático.

+1

Puede obtener una sintaxis más natural mediante el uso de un operador de conversión con plantilla en una variable global. Ver mi respuesta ... :) –

52

Su sugerencia (llamar al constructor shared_ptr<T> sin ningún argumento) es correcta. (Llamar al constructor con el valor 0 es equivalente.) No creo que esto sea más lento que llamar al vec.push_back() con un shared_ptr<T> preexistente, ya que se requiere una construcción en ambos casos (construcción directa o construcción de copia).

Pero si quieres sintaxis "mejor", puede probar con el siguiente código:

class { 
public: 
    template<typename T> 
    operator shared_ptr<T>() { return shared_ptr<T>(); } 
} nullPtr; 

Esto declara un único objeto global nullPtr, que permite la siguiente sintaxis natural:

shared_ptr<int> pi(new int(42)); 
shared_ptr<SomeArbitraryType> psat(new SomeArbitraryType("foonly")); 

... 

pi = nullPtr; 
psat = nullPtr; 

Nota que si usa esto en varias unidades de traducción (archivos fuente), tendrá que dar un nombre a la clase (por ejemplo, _shared_null_ptr_type), mover la definición del objeto nullPtr a un archivo .cpp separado y agregar declaraciones extern en t el archivo de encabezado donde se define la clase.

+0

nice idea dude. Tuve que hacer +1 que: p pero tenga en cuenta la respuesta aquí http://stackoverflow.com/questions/395685/how-do-you-choose-between-a-singleton-and-an-unnamed-class/395738# 395738 –

+0

Gracias chicos. :) Mirando la publicación de litb sugiere que la clase realmente debería ser nombrada. –

+0

algunos nombres tontos: nullPtrT, NullPtrType, nullPtr_t. lo que sea :) encontré que añaden un _t cuando solo hay una instancia de algo (como, nothrow_t y nullptr_t). –

17

Bueno, esto es legal:

shared_ptr<Foo> foo; /* don't assign */ 

Y en este estado, que no apunta a nada.Incluso se puede probar esta propiedad:

if (foo) { 
    // it points to something 
} else { 
    // no it doesn't 
} 

¿Por qué no hacer esto:

std::vector < shared_ptr<Foo> > vec; 
vec.push_back (shared_ptr<Foo>); // push an unassigned one 
1

Aquí hay algo que creo que es un poco más simple y funciona bien

(recordemos que typedef es su amigo):

#include <cstdlib> 
#include <vector> 
#include <iostream> 
#include <boost/shared_ptr.hpp> 

typedef boost::shared_ptr< std::vector<char> > CharVecHandle; 

inline CharVecHandle newCharVec(std::vector<char>::size_type size) { 
    return CharVecHandle(new std::vector<char>(size)); 
} 

inline CharVecHandle newCharVec(void) { 
    return CharVecHandle(); 
} 

int main (void) 
{ 
    CharVecHandle cvh = newCharVec(); 

    if (cvh == NULL) 
     std::cout << "It's NULL" << std::endl; 
    else 
     std::cout << "It's not NULL" << std::endl; 

    std::vector<CharVecHandle> cvh_vec; 

    cvh_vec.push_back(newCharVec(64)); 
    cvh_vec.push_back(newCharVec()); 

    // or call the NULL constructor directly 
    cvh_vec.push_back(CharVecHandle()); 

    return EXIT_SUCCESS; 
} 
+0

Claro, un 'typedef' es más agradable de mirar que' boost :: shared_ptr ', y el OP parece estar preocupado solo con un solo tipo 'Foo', en cuyo caso' typedef' encaja muy bien. Si desea evitar una proliferación de 'typedef's para diferentes tipos de punteros inteligentes, mi enfoque es mejor, creo. Sin embargo, no estoy seguro de lo que intenta demostrar con sus funciones 'newCharVec()', ¿puede explicarlo? –

+0

@j_random_hacker: El propósito de las funciones 'newCharVec' es el mismo que typedef, conveniencia y consistencia. Menos caracteres para escribir y coherencia en la creación de objetos reales y objetos NULL. La cuestión es que, incluso si estuviera usando el método de la plantilla, probablemente todavía crearía un typedef. Viniendo de un fondo 'C' cada vez que veo una declaración de tipo demasiado complicada, mi primer instinto es escribirlo. Teniendo esto en cuenta, no estoy seguro si realmente hay una razón objetiva para elegir uno u otro método, puede tratarse de un tema de estilo o preferencia personal. –

+0

Bueno, una razón para preferir mi enfoque es que, debido a que mi 'nullPtr' es de tipo agnóstico, funcionará en plantillas de funciones cuando se manipulen variables cuyo tipo es desconocido, mientras que el suyo no lo hará. P.ej. Puedo escribir una plantilla de función 'template push_a_null_ptr (vector > & v) {v.push_back (nullPtr); } ', que funcionará para todos los tipos' T'. Admito que no es una gran ventaja, pero no veo inconvenientes. –

9

En C++ 0x, sólo tiene que convertir de nullptr-std::shared_ptr:

std::vector< boost::shared_ptr<Foo> > vec; 
vec.push_back(nullptr); 
Cuestiones relacionadas