Utilizzo di oggetti in più contenitori in C ++

0

Nei casi in cui vi è un desiderio che gli oggetti siano "condivisi" tra più contenitori, mi piacerebbe sapere qual è la migliore pratica in C ++. Ad esempio, quando si implementano alcuni algoritmi di percorso (come A *), ho implementato una matrice bidimensionale di Nodi (classe definita dall'utente), e voglio anche avere un Set, dove verranno aggiunti e rimossi Nodi specifici durante l'esecuzione dell'algoritmo. Tuttavia, quando aggiungo un Nodo nel Set, voglio memorizzare questo Nodo specifico (e non una copia), in modo che le modifiche negli oggetti del Set siano visibili anche nell'array bidimensionale. Immagino che ci siano 2 approcci:

  • conserva diverse copie dei Nodi in Set e nell'array 2-d, e crea anche un meccanismo che sincronizzi le copie, in modo che le modifiche vengano passate dall'una all'altra. Tuttavia, sarebbe difficile da implementare e consumerebbe molta memoria, a causa di molte copie ridondanti dei nodi.
  • i 2 contenitori (l'array bidimensionale e l'insieme) tengono semplicemente puntatori ai nodi. Quindi, quando voglio aggiungere un nodo specifico nell'insieme, recupero il puntatore a questo nodo dall'array 2-d e inserisco il puntatore nel Set.

Da allora, ho concluso che la seconda soluzione deve essere quella giusta, vorrei porre le seguenti domande:

  1. Durante l'apprendimento del C ++, ho trovato libri che consigliano di evitare di creare contenitori con puntatori . Quindi, dovrei accettare questo caso come eccezione alla regola?
  2. Come dovrei progettare in modo ottimale l' inizializzazione dei nodi e la distruzione (liberazione delle risorse), dal momento che sia l'array 2-d che il Set manterranno i puntatori?
posta Dimos 07.06.2015 - 23:23
fonte

2 risposte

3

During learning C++, I have found books recommending to avoid creating containers with pointers. So, should I just accept this case as an exception to the rule ?

No, masterizza i libri. Non c'è niente di speciale in T * che lo rende inadatto in un contenitore.

How should I optimally design the initialization of the Nodes and the destruction (freeing of resources), since both the 2-d array and the Set will hold pointers ?

Utilizza std::shared_ptr , che usa il refcounting per gestire più proprietari.

A giudicare dal contenuto del tuo post, ho intenzione di affermare che sei in uno stato di puntatore pre-smart, quindi lascia che ti dia un consiglio fondamentale. Non usare mai new e delete , perché è quasi impossibile scrivere programmi corretti con loro e questa è solo la punta dell'iceberg nei modi in cui tutto questo non si adatta completamente ai programmi banali, ad esempio , eccezioni.

Utilizza sempre un oggetto di conservazione delle risorse dedicato per gestire le risorse. Mai liberarli da soli.

    
risposta data 07.06.2015 - 23:37
fonte
0

Prima di tutto, i contenitori che contengono puntatori grezzi sono solo problematici perché quei puntatori potrebbero diventare non validi / non aggiornati in qualsiasi momento (dal punto di vista del contenitore del puntatore). Lo stesso vale per i contenitori di iteratori.

Possibili soluzioni a cui posso pensare:

1) L'opzione un po 'meno pericolosa: Archiviare gli oggetti in un contenitore stabile basato su nodo come std :: list, std :: map o std :: set in modo che un puntatore / iteratore a un singolo oggetto è garantito che rimanga valido fino a quando quel particolare oggetto non è stato rimosso dal contenitore. Ciò richiede ancora una notevole quantità di sincronizzazione da parte tua, quindi raramente è la mossa migliore, ma è quasi sempre un'opzione.

2) Un'opzione sicura: usa i puntatori condivisi in entrambi i contenitori, in modo che tutte le risorse siano garantite dalla lingua per essere ripulite correttamente in modo deterministico.

3) Un'altra opzione sicura: non utilizzare affatto puntatori / iteratori e trovare un altro modo per fare riferimento all'array 2D dal set. Ad esempio, il set potrebbe contenere std :: coppie di interi che rappresentano gli indici nell'array 2D.

4) L'opzione ideale: rifatta il tuo codice in modo da non aver bisogno di due strutture dati in primo luogo. La necessità di memorizzare un contenitore di puntatori / iteratori sarebbe un odore di codice, anche se fosse

Quale di queste opzioni è la migliore dipende pesantemente dal tuo codice. Ad esempio, se il Set di cui parli esiste esclusivamente all'interno di una funzione doAStar () che prende un riferimento a un array 2D e non è coinvolta alcuna concorrenza, io personalmente andrei al # 3. In questo caso, la matrice è garantita per non cambiare durante la chiamata di funzione, quindi i puntatori intelligenti sono eccessivi e il Set è strettamente temporaneo, quindi il "codice odore" non è realmente lì.

    
risposta data 07.06.2015 - 23:47
fonte

Leggi altre domande sui tag