2017-11-30 3 views
0

Ich habe folgende Zuordnerklasse:Ist es ein Geruch, Dinge in einem Parameter zu sammeln, der als Referenz in C++ zurückgegeben wird?

class ObjectMapper { 
public: 
    std::map<uint32_t, uint32_t>& getMappingForObject(
      Object* object); 

private: 
    std::unordered_map<Object*, std::map<uint32_t, uint32_t>> m_objMapping; 
}; 

, deren Umsetzung so etwas wie dieses:

std::map<uint32_t, uint32_t>& ObjectMapper::getMappingForObject(
     Object* object) { 
    const auto mappingTableIterator = m_objMapping.find(object); 
    if (mappingTableIterator == m_objMapping.end()) { 
     auto it = m_objMapping.emplace(object, 
              std::map<uint32_t, uint32_t>()); 
     return it.first->second; 
    } 
    return mappingTableIterator->second; 
} 

diese So kann der Anrufer tun:

std::map<uint32_t, uint32_t>& mappingTable = 
      objMapper.getMappingForObject(object); 

Und gehen Sie auf und fügen/Dinge entfernen in mappingTable.

Ist das ein gutes Muster in C++? Ich glaube, dass dies einen Referenzausgangsparameter verwendet, um Besitz zu übergeben, was ein Geruch ist, aber ich bin mir nicht sicher. Gibt es eine Alternative, die schöner ist?

+2

Ihr 'getMappingForObject' ist nur' operator [] 'für Maps ... –

+2

Sie haben keinen Besitz übergeben, Ihre' unordered_map' hat nur einen rohen Zeiger. Sie haben keinen Ausgabeparameter. Ob etwas ein "Code-Geruch" ist, ist auch sehr eigensinnig. –

+0

Was bedeutet es genau zu fragen "Ist es ein Geruch?" Vielleicht sollte der Titel weniger umgangssprachlich sein. –

Antwort

0

Umschreiben Sie Ihre Funktion in einfacheren Begriffen zeigen, dass es korrekt ist, solange der Aufrufer das Ergebnis für die spätere Verwendung nicht speichert und weiß, dass das Ändern der Karte die Referenz ungültig macht. Lassen Sie uns darauf zurückkommen ...

können Ihre ursprüngliche Funktion neu geschrieben werden als:

std::map<uint32_t, uint32_t>& ObjectMapper::getMappingForObject(Object* object) 
{ 
    if (m_objMapping.count(object) == 0) 
    { 
     // a new object, remove test if nothing special needs to be done. 
    } 
    return m_objMapping[object]; 
} 

Als allgemeine Regel gilt, sollten Sie davon ausgehen, dass das ObjectMapper Objekt wird den Umfang des Anrufers überleben. Der zurückgegebene Verweis stammt aus unseren eigenen Objektdaten. Daher sollte es keine Lebensdauerprobleme geben, solange der Aufrufer die Regeln befolgt.

Wenn Sie beabsichtigen, die zurückgegebene Karte für eine längere Zeit (mehr als ein paar Millisekunden) oder in einer Multithread-Anwendung zu verwenden, möchten Sie stattdessen mit einer Kopie der Karte arbeiten. um die Zeit zu verkürzen, in der Ihre Datenstruktur gesperrt ist, und um Änderungen an Ihren Kartendaten zu "transaktionalisieren".

Verwandte Themen