Come gestire le modifiche al design per la deprecazione auto_ptr in C ++ 11?

7

Stiamo testando una libreria in C ++ 11 (cioè, -std=c++11 ). La libreria utilizza auto_ptr e questo modello:

Foo* GetFoo()
{
    autoptr<Foo> ptr(new Foo);

    // Initialize Foo
    ptr->Initialize(...);

    // Now configure remaining attributes
    ptr->SomeSetting(...);

    return ptr.release();
}

C ++ 11 deprecato auto_ptr , quindi vogliamo allontanarci da esso.

Tuttavia, il codice supporta sia C ++ 03 che C ++ 11, quindi non è semplice come% yout coating%. Vale anche la pena ricordare che la libreria non ha dipendenze esterne. Usa C ++ 03; e non usa Autotools, Cmake, Boost, ...

Come dovremmo gestire le modifiche al design per allontanarci da auto_ptr per C ++ 11 mantenendo la compatibilità con C ++ 03?

    
posta jww 29.07.2015 - 10:09
fonte

1 risposta

9

Sotto molti aspetti std::unique_ptr è stato realizzato per essere sostituito (ma più sicuro) per std::auto_ptr , quindi ci dovrebbero essere pochissime (se ce ne sono) modifiche al codice richieste diverse da (come chiedi) indirizzando il codice per utilizzare unique_ptr o auto_ptr .

Ci sono alcuni modi per farlo (e ognuno ha i propri compromessi con le liste) di seguito. Dato il codice di esempio fornito, preferirei una delle due prime opzioni .

Opzione 1

#if __cplusplus >= 201103L
template <typename T>
using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif

Compromessi;

  • Si introduce il nome auto_ptr nello spazio dei nomi globale; puoi mitigarlo definendo che è il tuo spazio dei nomi "privato"
  • Una volta migrata in C ++ 17 (credo che auto_ptr sarà completamente rimossa) puoi più facilmente cercare e sostituire

Opzione 2

template <typename T>
struct my_ptr {
    #if __cplusplus >= 201103L
    typedef std::unique_ptr<T> ptr;
    #else
    typedef std::auto_ptr<T> ptr;
    #endif
};

Compromessi;

  • Probabilmente più ingombrante con cui lavorare, tutti gli auto_ptr attuali devono essere cambiati nel codice in qualcosa come my_ptr<T>::ptr
  • Maggiore sicurezza i nomi non vengono introdotti nello spazio dei nomi globale

Opzione 3

Piuttosto controverso, ma se sei pronto a sopportare le avvertenze di avere una classe std come 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

Compromessi;

  • Non tentare di utilizzare la classe ereditata dove ci si aspetterebbe una base virtuale (in particolare il distruttore non virtuale w.r.t. Non che questo dovrebbe essere un problema nel caso, ma sii consapevole di ciò
  • Anche in questo caso, le modifiche al codice
  • Scomparamenti di spazio dei nomi potenziali - tutto dipende da come viene utilizzata la classe pointer per iniziare con

Opzione 4

Avvolgi i puntatori in una nuova classe e aggrega le funzioni richieste al membro

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(); }
};

Compromessi;

  • Un po 'estremo quando tutto ciò che vuoi veramente è "scambiare" le implementazioni
risposta data 29.07.2015 - 11:31
fonte

Leggi altre domande sui tag