L'unica volta (che ho dove può essere utile) dove operator[]
può essere utile quando si desidera impostare il valore di una chiave (sovrascriverlo se ha già un valore) e si sa che è sicuro sovrascrivere (che dovrebbe essere poiché si dovrebbe utilizzare puntatori intelligenti, non puntatori grezzi) ed è economico per il valore predefinito e, in alcuni contesti, il valore dovrebbe avere no-throw construction and assignment.
ad es. (Simile al tuo primo esempio)
std::map<int, std::unique_ptr<int>> m;
m[3] = std::unique_ptr<int>(new int(5));
m[3] = std::unique_ptr<int>(new int(3)); // No, it should be 3.
caso contrario, ci sono alcuni modi per farlo a seconda del contesto, tuttavia mi sento di raccomandare di usare sempre la soluzione generale (in questo modo non si può sbagliare).
Trova un valore e crearlo se non esiste:
1. Soluzione Generale (consigliato in quanto funziona sempre)
std::map<int, std::unique_ptr<int>> m;
auto it = m.lower_bound(3);
if(it == std::end(m) || m.key_comp()(3, it->first))
it = m.insert(it, std::make_pair(3, std::unique_ptr<int>(new int(3)));
2. Con la costruzione di default a buon mercato di valore
std::map<int, std::unique_ptr<int>> m;
auto& obj = m[3]; // value is default constructed if it doesn't exists.
if(!obj)
{
try
{
obj = std::unique_ptr<int>(new int(3)); // default constructed value is overwritten.
}
catch(...)
{
m.erase(3);
throw;
}
}
3.Con la costruzione di default a buon mercato e l'inserimento tiro alcun valore
std::map<int, my_objecct> m;
auto& obj = m[3]; // value is default constructed if it doesn't exists.
if(!obj)
obj = my_objecct(3);
Nota: Si potrebbe facilmente avvolgere la soluzione generale in un metodo di supporto:
template<typename T, typename F>
typename T::iterator find_or_create(T& m, const typename T::key_type& key, const F& factory)
{
auto it = m.lower_bound(key);
if(it == std::end(m) || m.key_comp()(key, it->first))
it = m.insert(it, std::make_pair(key, factory()));
return it;
}
int main()
{
std::map<int, std::unique_ptr<int>> m;
auto it = find_or_create(m, 3, []
{
return std::unique_ptr<int>(new int(3));
});
return 0;
}
Nota che passo davanti a un metodo factory su modelli, invece di un valore per il caso di creazione, in questo modo non c'è un sovraccarico quando il valore è stato trovato e non è necessario creare. Poiché lambda viene passato come argomento modello, il compilatore può scegliere di inserirlo.
In generale, le regole "mai fare questo" sono cattive. Ci sono casi in cui hai effettivamente bisogno di qualcosa e dovresti infrangere la regola. –
(Su una nota correlata, vedere [Boost Pointer Containers] (http://www.boost.org/doc/libs/1_48_0/libs/ptr_container/doc/ptr_container.html) per i contenitori che manterranno i puntatori e li distruggeranno quando necessario) –
Evitare di usare [] e preferire inserire/trovare. Questo è un buon senso, come evitare variabili non inizializzate, avvisi del compilatore ecc. – rmflow