2008-11-06 18 views
9

std::auto_ptr está roto en VC++ 8 (que es lo que usamos en el trabajo). Mi principal queja es que permite auto_ptr<T> x = new T();, lo que por supuesto conduce a accidentes horribles, mientras que es fácil de hacer por error.Reemplazando auto_ptr en VC++ 8

Desde un answer a otra pregunta aquí en stackoverflow:

Nota que la aplicación de std :: auto_ptr en Visual Studio 2005 es terriblemente roto. http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842

Quiero usar

  • boost::scoped_ptr, para los punteros que no debe pasar la propiedad.
  • boost::shared_ptr, para punteros en contenedores y en otros lugares donde se necesiten.
  • std::auto_ptr, para punteros que deben/pueden pasar la propiedad.

Pero desde std::auto_ptr se rompe para mí, me pregunto cuál sería el mejor enfoque:

  • Reemplazar std::auto_ptr con algo de la red. Me gusta esto this uno de Rani Sharoni (no lo he probado todavía).
  • Use boost::shared_ptr en su lugar. Por supuesto, funcionará, aunque habrá algunos gastos menores que no me importan. Pero quiero usar auto_ptr para señalar la intención del puntero. (Consulte this respuesta para una votación sobre este enfoque.)
  • Nunca tendré que pasar la propiedad en la práctica, así que no debería preocuparme por esto.

Actualización: Esto es lo que hice: copié la implementación auto_ptr citada por Rani Sharoni. From here.

hizo algunas pruebas menores:

class T 
{ 
public: 
    T() { 
     OutputDebugStringA("T\n"); 
    }; 
    ~T() { 
     OutputDebugStringA("~T\n"); 
    }; 
}; 

{ 
    fix::auto_ptr<T> x(new T); // This just works. 
} 
{ 
    fix::auto_ptr<T> x = (new T); // Doesn't compile. Great! 
} 
{ 
    fix::auto_ptr<T> x = fix::auto_ptr<T>(new T); // Transfer of ownership works also. 
} 

Por supuesto, estas pruebas son de ninguna manera exhaustiva y no se debe confiar en ellos. Implementar una clase de plantilla segura de excepción es un asunto peliagudo. Al menos esto funciona mejor que el construido en uno.

Nota: No sé si todavía puedo utilizar esta implementación, con respecto a los derechos de autor. He enviado un correo electrónico a Rani y estoy esperando una respuesta. Actualizaré esta publicación cuando sepa más. Se otorga permiso para que todos puedan usar la implementación auto_ptr de Rani Sharoni como lo deseen.

Gracias por todas sus respuestas.

+0

Pasar la propiedad no es algo que sucede a menudo, pero proporciona una forma clara de auto-documentación como parte del código. –

+0

Esa es exactamente mi idea. Adoro el código de auto-documentación. –

Respuesta

7

movimiento para impulsar punteros inteligentes.

Mientras tanto, es posible que desee extraer una implementación auto_ptr que funcione de una STL anterior/otra, por lo que tiene un código de trabajo.

Creo que la semántica de auto_ptr está fundamentalmente rota: ahorra tipeo, pero la interfaz en realidad no es más simple: todavía tiene que rastrear qué instancia es el propietario actual y asegurarse de que el propietario se va.

unique-ptr "corrige" que, al realizar la liberación, no solo renuncia a la propiedad, sino que también establece el RHS como nulo. Es el reemplazo más cercano para auto-ptr, pero con su semántica diferente no es un reemplazo directo.

Hay un artículo introductorio al boost smart pointers, por, ejem, yo.

+0

Leí tu artículo. Está muy bien escrito. Gracias. En la mayoría de los casos, los indicadores de refuerzo estarán bien. No estoy seguro de cómo debo lidiar con auto_ptr todavía. Estoy tratando de establecer una nueva guía para los indicadores inteligentes en el trabajo en este momento, así que será mejor que lo resuelva. –

+0

Er, 'auto_ptr' también establece que RHS anule cualquier copia. ¡Así es como renuncia a la propiedad! –

+0

IIRC algunas implementaciones (o la inicial) no lo hicieron. – peterchen

0

Utilice boost :: shared_ptr/boost :: scoped_ptr. Será el puntero inteligente preferido en los próximos estándares C++ (ya está en TR1).

Editar: por favor, encontrar una discusión relacionada aquí: Idiomatic use of std::auto_ptr or only use shared_ptr?

+0

Preferido es una palabra fuerte. shared_ptr y auto_ptr hacen cosas diferentes. –

+0

Sí, eso es cierto: generalmente usaría el shared_ptr, pero eso puede deberse al hecho de que nunca tuve ningún caso de uso para el auto_ptr. – MP24

+0

Ya estoy siguiendo las otras discusiones sobre el puntero inteligente aquí en stackoverflow, pero gracias todavía. Ya soy de la opinión que me gustaría utilizar de forma automática, compartida y de ámbito. Pero debido a mi compilador (y su implementación de biblioteca), no estoy seguro de qué hacer. –

1

¿Por qué cree std :: auto_ptr <> se rompe.

¡Hubiera pensado que algo tan malo como eso habría sido informado al comité de normas!

¿Quiere decir que usted necesita:

std::auto_ptr<T> x(new T); // Use the explicit constructor. 
+0

No está roto en todas partes. Solo específicamente en VC++ 8. VC++ 9 tiene una mejor implementación. –

+2

Sí. O bien std :: auto_ptr x (nueva T); o std :: auto_ptr x = std :: auto_ptr (nueva T); funcionará. std :: auto_ptr x = new T; no debe compilar. Lo hace y el resultado no está definido. –

+0

¿Qué quiere decir con "los resultados no están definidos"? ¿No debería llamar implícitamente al constructor? Por supuesto, esto todavía es (discutiblemente) un inconveniente. –

3

¿Ha considerado el uso de STLPort?

+0

Eso estaría en línea con la idea de 'Reemplazar la implementación de auto_ptr'. Espero poder hacer algo un poco menos que introducir una nueva implementación de STL en nuestro proyecto. Tiene dos años y somos cinco personas que lo escriben. Pero gracias de cualquier manera. –

+0

Reemplazar técnicamente su implementación de STL "no debería" causar ningún problema. Si algo se eliminaría entonces. Pero si tienes un código que depende de esos problemas, entonces estás jodido. Teniendo en cuenta que se trata de una solución de "arrastrar y soltar", tal vez vale la pena considerarlo si tiene ancho de banda para las pruebas. –

+0

Yo en segundo lugar. Reemplazar el STL debería ser una simple cuestión de configurar el proyecto para usar STLPort (que creo que usa el STL nativo si no está roto). –

2

Utilice un unique_ptr. Creo que estos fueron introducidos para ser un mejor auto_ptr.

http://www.boost.org/doc/libs/1_35_0/doc/html/interprocess/interprocess_smart_ptr.html#interprocess.interprocess_smart_ptr.unique_ptr

De hecho, tengo entendido que auto_ptr puede estar desfasada y en que:

http://objectmix.com/c/113487-std-auto_ptr-deprecated.html

+0

Boost tiene uno disponible, aunque no estoy 100% seguro de qué versiones de VC tienen la conformidad estándar en el lenguaje suficiente para poder admitirlo. –

+0

Además, ¿por qué solo hay un impulso :: interprocess :: unique_ptr y no boost :: unique_ptr. Me gustaría aprender más antes de tomar este camino. Las propuestas estándar para unique_ptr parece que solo funcionan en compiladores nuevos estándar (gcc). –

+0

Además, creo que desaprobar auto_ptr solo sería relevante una vez que sea reemplazado por unique_ptr. –

0

Por lo que yo recuerdo, no era eso:

auto_ptr<T> x = auto_ptr<T>(new T()); ?? 
+1

Eso es demasiado largo - 'auto_ptr x (nuevo T())' hará lo mismo de una manera menos indirecta. –

0

No es una respuesta, pero para el interés general de las personas para quienes estos errores son relevantes. Hay one more related bug con VC8 auto_ptr, que tiene que ver con las transmisiones implícitas. Es probablemente el más malo del grupo, porque otros errores solo te permiten compilar código que de otra manera sería ilegal según Standard sin fallar, pero al menos el código compatible funciona bien. Con este error, el código que es realmente compatible no funciona correctamente.

El problema es esto. Standard especifica los constructores auto_ptr y los operadores de conversión de tal manera que admiten upcasting implícito de auto_ptr s, al igual que con los punteros normales. Sin embargo, la implementación VC8 de eso hace un reinterpret_cast en lugar de un static_cast allí. Naturalmente, no solo esto es U.B. por la letra del estándar, pero también se rompe con múltiples clases base y/o herencia virtual. Aquí está un ejemplo de código legal roto por esto:

struct Base1 { int x; }; 
struct Base2 { int y; }; 
struct Derived : Base1, Base2 {}; 

std::auto_ptr<Derived> createDerived() 
{ 
    return std::auto_ptr<Derived>(new Derived); 
} 

std::auto_ptr<Base2> base2(createDerived()); 

En uno de mis últimos trabajos, cuando nos encontramos con este problema en la producción, terminamos simplemente remendar las cabeceras de nosotros mismos (que es una solución de 2 líneas trivial) .