Accesso ai membri di un insieme mediante una delle loro proprietà

4

Spesso mi trovo nella situazione in cui un oggetto contiene un insieme di oggetti e voglio accedere a uno di questi oggetti in base a una delle sue proprietà.

Come faccio attualmente in C ++, metto questi oggetti in una mappa, dove la chiave è una copia della proprietà dell'oggetto. Ad esempio:

map.insert(make_pair(obj.getName(), obj));

Tuttavia, questo non mi sembra giusto, perché non definisco una mappatura - la relazione tra la proprietà e l'oggetto è già definita.

C'è un modo migliore per farlo?

    
posta Oebele 03.03.2016 - 13:24
fonte

2 risposte

1

Ci sono due problemi.

  1. Che cos'è la mappatura?
  2. La mappatura può cambiare?

Per prima cosa, non preoccuparti della mappatura già definita. Finché il nome è l'identità dell'oggetto (si pensi alla chiave primaria in un database relazionale), allora è una chiave naturale e assolutamente dovrebbe essere usata come maniglia per il proprio oggetto. Non stai "definendo" nulla, stai semplicemente usando una proprietà del tuo oggetto.

L'altro problema è se la tua chiave è immutabile o meno e una proprietà immutabile dell'oggetto.

Con C ++, il nome nella chiave e nell'oggetto saranno oggetti separati "di proprietà" dai rispettivi contenitori (la mappa e l'oggetto). Una stringa C ++ è modificabile. Inoltre, se il nome può essere impostato su una nuova stringa sull'oggetto, questa è un'altra possibile modifica.

Penso che se si rende la chiave const e il nome const sull'oggetto, si attenuano le preoccupazioni che potrebbero non essere sincronizzati.

    
risposta data 03.03.2016 - 21:50
fonte
1

Mi piacerebbe condividere un approccio che ha funzionato per me in passato:

struct Thing {
  std::string const property; // This is an important assumption
  int dummy;
};

Voglio fare riferimento al property delle cose, quindi uso std::reference_wrapper . Supponendo che la ricerca avvenga molto più spesso che cambiando le cose, memorizzerei le cose in un std::vector . Per ottenere una rapida ricerca, utilizzerei una mappa dai riferimenti alle proprietà ai riferimenti alle cose.

std::vector<Thing> things;
std::map<
  std::reference_wrapper<std::string const>,
  std::reference_wrapper<Thing>> lookup;

Effettuare una ricerca è semplice, data una stringa p :

Thing & i_want = lookup.at(p).get();

L'inserimento delle cose deve occuparsi di riferimenti eventualmente invalidati:

// Thing newcomer
auto old_capacity = things.capacity();
things.push_back(newcomer); // or emplace
if (old_capacity == things.capacity()) {
  lookup.emplace(
    std::ref(things.back().property),
    std::ref(things.back()));
} else {
  lookup.clear();
  for (auto const & t : things) {
    lookup.emplace(
      std::ref(t.property), std::ref(t));
  }
}

Rimuovere le cose è lasciato come esercizio al lettore. L'utilizzo di una struttura dati diversa rispetto a un vettore come archiviazione di supporto può essere preferibile se l'aggiunta o la rimozione di cose avviene più spesso.

Si noti che il codice sopra riportato è solo un abbozzo dell'idea. Sono sul mio cellulare, dove è piuttosto difficile scriverlo e testarlo.

    
risposta data 08.03.2016 - 01:39
fonte

Leggi altre domande sui tag