2015-07-14 30 views
5

Per il mio GUI ho bisogno di una classe con le seguenti finalità di gestire i controlli (finestre, pulsanti, ecc)Come creare un contenitore sicuro per la copia con std :: list iterators memorizzati in un vettore std in C++?

  • accesso casuale agli elementi da [index]
  • accesso casuale agli elementi da ["key"]
  • stabilità puntatore , quindi ptr=&container[index] non cambierà se gli elementi vengono aggiunti o cancellati
  • copia sicurezza. Tutti gli elementi devono essere memorizzati nel contenitore e copiati se '=' viene utilizzato come container2=conatiner1 (copia profonda)
  • l'ordine degli elementi nell'elenco deve essere modificabile, tuttavia i puntatori agli elementi devono rimanere validi. Se ptr1=container[1] e ptr2=container[2], poi dopo lo scambio dell'ordine di 1 e 2, e ptr1==container[2]ptr2==container[1]

sono giunto alla conclusione che std :: elenco fornisce la stabilità per i puntatori che ho bisogno e std :: vector casuale accesso. Quindi ho l'idea di memorizzare una tupla di stringa e iteratore standard in un vettore. Tuttavia, gli iteratori non sono validi dopo la copia del contenitore.

Qualche suggerimento su come affrontare al meglio questo problema?

Qui il codice principale dell'approccio attuale (solo le parti più importanti sono incluse):

template < class T > 
class ControlList 
{ 
    struct Tuple{std::string first;typename std::list<T>::iterator second;}; 
    std::vector<Tuple> list; 
    std::list<T> objects; 

    inline T& operator [](int i) 
    { 
     return *list[i].second; 
    } 
    inline T& operator [](std::string s) 
    { 
     loopi(0,vlist.size()) 
     if(s==vlist[i].first) 
      return *vlist[i].second; 
    } 
} 

L'accesso stringa è lento, ma di solito il contenitore non ha più di 10 elementi e la sua usato raramente in programma .

Aggiornamento:

Il puntatore condiviso è già buono, ma non può risolvere per la copia profonda che mi serve. Diciamo che ho window2 = window1. Ora se ho un puntatore condiviso, premendo un pulsante in window2 si preme anche lo stesso pulsante in window1, che non è voluto. Ho davvero bisogno di una nuova istanza di tutti gli oggetti contenuti nel contenitore.

È possibile sovrascrivere il costruttore di copie per creare nuove istanze degli oggetti a cui fanno riferimento i puntatori intelligenti?

Entrambi, finestre e pulsanti sono memorizzati in un ControlList, in cui una finestra contiene più elenchi.

Update2:

Override il costruttore di copia e il costruttore assegnazione ha apparentemente risolto il problema

Update3:

Ho appena rilasciato l'interfaccia grafica di questa classe è stato destinato per meno di MIT.

Download here.

+0

È questo C++ 11 o C++ 03? – VermillionAzure

+0

Si dovrebbe avere un singolo contenitore con la modellazione dei requisiti più generali (ovvero un vettore std :: vector di maniglie di elementi della GUI) e viste in quel contenitore (std :: vector :: iterator) –

+0

Per curiosità, si dice che "L'accesso alla stringa è lento", cos'è lento e quanto è importante la sua velocità? (Hai detto che non viene usato spesso, ma viene utilizzato nei momenti critici?) Ciò potrebbe potenzialmente influire sulla soluzione proposta. –

risposta

3

Se si sceglie di usare std::vector<std::pair<std::string, std::unique_ptr<T>>>, è possibile copiare gli elementi tuttavia si voleva, e il valore risultante sarebbe solo bisogno di un altro passo di indirezione di accesso.Ciò eliminerebbe gran parte della complessità che hai adesso con 3 diverse strutture. Come bonus, anche gli oggetti si ripuliscono automaticamente da solo.

Se si richiede semantica di osservatore proprietario con i puntatori, è possibile invece optare per std::shared_ptr<T> e std::weak_ptr<T>. I puntatori condivisi possono facilmente creare puntatori deboli, che agiscono come osservatori non proprietari che non influiscono sul conteggio dei riferimenti del puntatore condiviso.

Modifica: Solo per aggiungere, shared_ptr e gli altri puntatori intelligenti sono C++ 11 e successivi-esclusivi. Se desideri soluzioni compatibili con C++ 03, puoi guardare alle implementazioni di Boost del passato o magari crearne uno tu stesso osservando le specifiche di C++ 11/14.

Edit2: Ecco il codice per assistere:

http://coliru.stacked-crooked.com/a/a9bf52e5428a48af

#include <vector> //vector 
#include <memory> //smart pointers 
#include <utility> //pair 
#include <string> //string 
#include <iostream>//cout 

template <class T> 
class Container { 
public: 
    inline void push(const std::string& s, const T& t) { 
     objects.push_back(std::pair<std::string, std::shared_ptr<T>>(s, std::make_shared<T>(t))); 
    } 

    inline T& operator [](const size_t& i) 
    { 
     return *(objects[i]->second); 
    } 
    inline T& operator [](const std::string& s) 
    { 
     for (auto it : objects) { 
      if(s == it.first) { 
       return *(it.second); 
      } 
     } 

     //welp, what do you do here if you can't find it? 
    } 
private: 
    std::vector<std::pair<std::string, std::shared_ptr<T>>> objects; 
}; 

int main() { 
    Container<int> cont; 
    std::string str {"hi"}; 
    int i {2}; 

    cont.push(str, i); 

    //This is good... 
    std::cout << cont["hi"] << std::endl; 

    //But undefined behavior! 
    std::cout << cont["02"] << std::endl; 
    return 0; 
} 
+0

Grazie per la risposta dettagliata. Ho adottato il tuo codice e sostituito la mia vecchia std: vector class, con struct Tuple {std :: string first, T second;}. Sfortunatamente l'intero sistema a finestre è stato incasinato e il framerate è sceso a 1/10. Aggiungerò i dettagli nella domanda originale –

+0

Ora funziona :) Sembra che fosse un bug da parte mia. Di nuovo! –

+0

@MarcoPolo È necessario accettare le risposte corrette .... – VermillionAzure