¿Cómo manejar los cambios de diseño para la desaprobación de auto_ptr en C ++ 11?

7

Estamos probando una biblioteca bajo C ++ 11 (es decir, -std=c++11 ). La biblioteca utiliza 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 desaprobado 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 auto_ptr . También vale la pena mencionar que la biblioteca no tiene dependencias externas. Utiliza 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 mantenemos la compatibilidad con C ++ 03?

    
pregunta jww 29.07.2015 - 10:09

1 respuesta

9

En la mayoría de los casos, std::unique_ptr se realizó para reemplazar (pero más seguro) el reemplazo de std::auto_ptr , por lo que debería haber muy pocos (si los hubiera) cambios de código requeridos además de (como usted preguntar) indicando al código que use unique_ptr o auto_ptr .

Hay algunas maneras de hacer esto (y cada una viene con sus propias compensaciones de listas) 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;

  • Introduces el nombre auto_ptr en el espacio de nombres global; puede mitigar esto definiéndolo como 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
};

Compensaciones;

  • Probablemente sea más complicado trabajar con él, todo el auto_ptr actual necesita cambiarse en el código a algo como my_ptr<T>::ptr
  • Para mayor seguridad, los nombres no se están introduciendo en el espacio de nombres global

Opción 3

Algo controvertido, pero si estás preparado para soportar 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 con el destructor no virtual). No es que esto deba ser un problema en el caso, pero sea consciente de ello
  • Nuevamente, el código cambia
  • No coinciden los espacios de nombres potenciales: todo depende de cómo se utiliza la clase de puntero para comenzar

Opción 4

Envuelva los punteros en una nueva clase y agregue las funciones necesarias 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;

  • Un poco extremo cuando lo único que quieres es "intercambiar" las implementaciones
respondido por el Niall 29.07.2015 - 11:31

Lea otras preguntas en las etiquetas