Estamos probando una biblioteca en C ++ 11 (es decir, -std=c++11
). La biblioteca usa auto_ptr
y este patrón:
Foo* GetFoo() { autoptr<Foo> ptr(new Foo); // Initialize Foo ptr->Initialize(...); // Now configure remaining attributes ptr->SomeSetting(...); return ptr.release(); }
C ++ 11 obsoleto auto_ptr
, por lo que queremos alejarnos de él.
Sin embargo, el código admite tanto C ++ 03 como C ++ 11, por lo que no es tan simple como quitar auto_ptr
. También vale la pena mencionar que la biblioteca no tiene dependencias externas. Usa C ++ 03; y no usa Autotools, Cmake, Boost, …
¿Cómo debemos manejar los cambios de diseño para alejarnos? de auto_ptr
para C ++ 11 mientras se conserva la compatibilidad con C ++ 03?
Comentarios
Respuesta
En la mayoría de los aspectos, el std::unique_ptr
se hizo para ser incluido (pero más seguro) reemplazo para std::auto_ptr
, por lo que debería haber muy pocos cambios de código (si es que se requieren alguno) que no sean (como preguntas) dirigiendo el código para que use unique_ptr
o auto_ptr
.
Hay algunas formas de hacerlo esto (y cada uno viene con su propia lista de compensaciones) a continuación. Dado el ejemplo de código proporcionado, preferiría cualquiera de las dos primeras opciones .
Opción 1
#if __cplusplus >= 201103L template <typename T> using auto_ptr = std::unique_ptr<T>; #else using std::auto_ptr; #endif
Compensaciones;
- Introduce el nombre
auto_ptr
en el espacio de nombres global ; puede mitigar esto definiendo que es su propio " espacio de nombres " privado - Una vez que migre a C ++ 17 (Creo que
auto_ptr
se eliminará por completo). Puede buscar y reemplazar más fácilmente
Opción 2
template <typename T> struct my_ptr { #if __cplusplus >= 201103L typedef std::unique_ptr<T> ptr; #else typedef std::auto_ptr<T> ptr; #endif };
Tradeoffs;
- Probablemente sea más complicado trabajar con todos los
auto_ptr
actuales que deben cambiarse en el código para algo comomy_ptr<T>::ptr
- Mejor seguridad, los nombres no se introducen en el espacio de nombres global
Opción 3
Algo controvertido, pero si está preparado para tolerar las advertencias de tener una clase std
como base
#if __cplusplus >= 201103L template <typename T> using my_ptr = std::unique_ptr<T>; #else template <typename T> class my_ptr : public std::auto_ptr<T> { // implement the constructors for easier use // in particular explicit my_ptr( X* p = 0 ) : std::auto_ptr(p) {} }; #endif
Compensaciones;
- No intente usar la clase heredada donde se esperaría una base virtual (en particular, el destructor no virtual). No es que esto deba ser un problema en el caso – pero tenlo en cuenta
- Nuevamente, cambios de código
- Posibles discrepancias en el espacio de nombres; todo depende de cómo se use la clase de puntero para comenzar
Opción 4
Envuelva los punteros en una nueva clase y agregue las funciones requeridas al miembro
template <typename T> class my_ptr { // could even use auto_ptr name? #if __cplusplus >= 201103L std::unique_ptr<T> ptr_; #else std::auto_ptr<T> ptr_; #endif // implement functions required... T* release() { return ptr_.release(); } };
Compensaciones;
- A un poco extremo cuando todo lo que realmente quieres es " intercambiar " las implementaciones
Comentarios
- Muy buena respuesta. De hecho, lo investigué un poco y llegaste al menos a tres de las pruebas que intenté. (Lo que te falta son las cosas específicas de OS X y Clang. OS X es un oso porque todavía usa el espacio de nombres TR1 para C ++ 03 a veces, y debes incluir cosas usando este método: Ningún tipo llamado ' unique_ptr ' en el espacio de nombres ' std ' al compilar bajo LLVM / Clang ).
- @jww. Yo ' m en OS X (XCode 6.4 y Apple LLVM versión 6.1.0 (clang-602.0.53) (basado en LLVM 3.6.0svn)) y no tengo problemas con C ++ 03/11 mezcla que no sea el espacio de nombres
tr1
que ya no está allí (uso libc ++ y no libstdc ++).Sé que tr1 no era normativo, pero no puedo ' encontrar ningún lugar en el borrador (aquí) que los archivos tenían que ser<tr1/...>
en absoluto, de hecho, menciona que solo están en el encabezado<memory>
, etc., en el archivotr1
espacio de nombres. - @jww. Supongo que dada una combinación particular de compilador, biblioteca y dispositivo de destino, es posible que deba hacer algunos soportes manuales más. De lo contrario, en OS X, considere pasar a clang y libc ++. Francamente, considero que libc ++ es la nueva biblioteca " nativa " de C ++ para OS X; yo lo usaría por defecto. No tengo forma de respaldar estas afirmaciones, aparte de que la historia de la relación clang / Apple y que las herramientas de GCC en OS X parecen desactualizadas (biblioteca) o simplemente eliminadas (hasta donde yo sé, GCC es un pequeño trozo de clang de todos modos ).
- " De lo contrario, en OS X, considere pasar a clang y libc ++ … " – sí, estoy de acuerdo contigo. Sin embargo, nos gustaría dejar que los usuarios tomen esa decisión y no forzarlos. (Toman implícitamente la elección cuando especifican (o no)
CXX=...
). - Aquí ' s el caso eso me está causando tantos problemas en OS X 10.7 y 10.8:
c++ -v -std=c++11 -x c++ - < /dev/null
.grep'd
los directorios de inclusión que se volcaron, y no incluyenunique_ptr
.
Respuesta
Opción 5: Alias directo.
#if __cplusplus >= 201103L template<typename T> using MyPtr = std::unique_ptr<T>; #else #define MyPtr std::auto_ptr #endif
Compensaciones:
-
Para versiones de idiomas más recientes, también conocido como C ++ 11 y posteriores, su tipo de alias se asigna al puntero inteligente correcto. Cualquier código de usuario que realmente dependa de las API específicas de std :: auto_ptr será marcado por el compilador, lo cual es la máxima garantía de que realmente se arreglará.
-
En Legacy En el modo c ++ 03, el alias de tipo es una macro. Esto es grosero, pero la sintaxis resultante
MyPtr<T>
será idéntica a la del caso C ++ 11 en el resto del código. -
Tienes que buscar y cambiar todas tus variables auto_ptr a
MyPtr
para configurar esto.
Comentarios
- Es ' muy poco claro a qué se refiere esto (y, como está redactado, no es ' una pregunta).
- @autophage Creo que es una respuesta … así que probablemente no sea una pregunta.
auto_ptr
tiene ámbito (es decir,std::auto_ptr
), es necesario o se puede obtener el puntero inteligente de algún otro espacio de nombres?Foo::Initialize
enFoo::Foo
.