Uso intelligente del puntatore nella libreria della GUI

1

Rolling my own GUI library per un side-project. Refactoring per usare puntatori intelligenti; tuttavia, ho riscontrato un problema.

Sono consapevole del fatto che non si desidera utilizzare i puntatori intelligenti attraverso i limiti della DLL per ovvi motivi. Ma mi sento sporco usando "nuovo" nel codice dell'applicazione. Vedi sotto:

// MYFINANCEAPP.H
class MyFinanceApp : public Application
{

MyFinanceApp() : mMainWindow(make_unique<Window>)
{
  mMainWindow->AddControl(new Button("testButton"));
}

private:
  std::unique_ptr<Window> mMainWindow;
};

// WINDOW.H
class Window
{
public:
  void AddControl(const Control& control)  //QUESTION: HOW DO I GET SMART POINTER HERE???
  {
    mControls.emplace_back(control)
  }
private:
  std::vector<std::unique_ptr<Control>> mControls;  //Want to use smart pointers so I am not responsible for managing...

};

È meglio usare lo stile e la semantica del C ++ 98 e gestirlo da solo. Ovviamente non voglio passare i puntatori intelligenti attraverso il limite dell'interfaccia (ad esempio AddControl), ma non voglio essere responsabile della gestione della durata dei controlli.

Inoltre, mi sento davvero sporco usando "new Button (" testButton ")).

    
posta keelerjr12 27.06.2017 - 17:34
fonte

2 risposte

5

In realtà, sì, vuoi per usare i puntatori intelligenti attraverso i confini della DLL.

Così facendo, a seconda del puntatore intelligente (Think std::shared_ptr<T> qui), ti assicuri che la stessa entità che elabora una risorsa lo riprenda anche nel modo appropriato.

Naturalmente anche std::unique_ptr<T, D> s è usato anche per questo, ma non oltre i confini della DLL poichè di solito non contiene il contesto della DLL di origine, std::default_delete<T> è senza stato.

Per inciso, c'è std::make_unique<T>() da C ++ 14.

    
risposta data 27.06.2017 - 17:50
fonte
2

Diversi problemi sono affrontati qui:

  • Innanzitutto, un unique_ptr è univoco e non può essere copiato. Quindi non è possibile passare il puntatore intelligente in base al valore. Lo stesso per, come sembra che tu intenda fare, passarlo per riferimento e copiarlo in un vettore non è possibile. Utilizza un puntatore univoco solo per oggetti conosciuti solo dal loro proprietario.
  • Se vuoi usare un puntatore intelligente come un puntatore o come un handle, con diverse copie di esso, dovresti usare shared_ptr . Puoi copiarlo come vuoi e se il conteggio degli usi diminuisce a zero, la memoria viene liberata come unique_ptr .
  • Il passaggio del puntatore allocato alla memoria attraverso i contorni della DLL è delicato, poiché è possibile utilizzare librerie diverse su entrambi i lati, il che potrebbe causare incongruenze.

Per tornare ai limiti della DLL, il codice del modello viene istanziato nella parte client della libreria. La versione diversa da quella utilizzata sul lato DLL potrebbe causare le incoerenze sopra menzionate, con allocazione e rilascio non corrispondenti. Se si utilizza sempre la stessa versione su entrambi i lati e si utilizza solo il collegamento dinamico (nessun codice o libreria che utilizza il collegamento statico), potrebbe anche funzionare perfettamente. Ma ovviamente non puoi assumere una condizione così favorevole se impacchetti la tua libreria per l'utilizzo da parte di terzi.

Sfortunatamente, non esiste una soluzione facile. Soprattutto se speri di liberare automaticamente in base al conteggio degli usi di ciò che accade sul lato client. Un'alternativa interessante sarebbe utilizzare un approccio Pimpl:

  • solo la libreria alloca e libera gli oggetti della GUI con o senza smar pointers
  • avvolgi questo puntatore nel modello (ad esempio, solo intestazione, istanziato sul lato client) con la tua logica di conteggio degli usi e chiama le funzioni della libreria per uccidere gli oggetti non utilizzati.
risposta data 27.06.2017 - 20:56
fonte

Leggi altre domande sui tag