Supponiamo di avere uno Storage
di alcuni Object
s con un metodo che aggrega i puntatori ad alcuni degli Objects
in un vettore. Come questo:C'è un modo per convertire std :: vector <const T*> in std :: vector <T*> senza allocazioni aggiuntive?
class Storage
{
public:
std::vector<Object*> aggregate_some_objects(); // non-const version
std::vector<const Object*> aggregate_some_objects() const; // const version
private:
std::unordered_map<size_t, Object> m_objects; // data is stored
// by-value in a non-vector container
}
In generale, non c'è modo per evitare di copia-incolla in attuazione coppie metodo non-const const + chiamando uno di loro dentro l'altro con l'aiuto di const_cast
. Qui tuttavia questo non è possibile perché i tipi di ritorno dei metodi sono diversi.
Il modo più semplice per evitare il copia-incolla qui sarebbe chiamare const
versione da una versione non const
e utilizzare il tornata std::vector<const T*>
per popolare un separato std::vector<T*>
. Tuttavia, ciò comporterebbe almeno 2 allocazioni di heap (una per ciascun vettore). Vorrei evitare le allocazioni associate al secondo vettore.
mi chiedo se non v'è modo di scrivere qualcosa di simile
template <typename T>
std::vector<T*> remove_const_from_vector_of_ptrs(std::vector<const T*>&& input)
{
std::vector<T*> ret;
// do some magic stuff here that does not involve
// more memory allocations
return ret;
}
Così, permettendo di scrivere
std::vector<const Object*> Storage::aggregate_some_objects() const
{
// non-trivial implementation
}
std::vector<Object*> Storage::aggregate_some_objects()
{
auto objects = const_cast<const Storage*>(this)->aggregate_some_objects();
return remove_const_from_vector_of_ptrs(std::move(objects));
}
Non esiste un metodo 'rilascio' in std::vector
(come std::unique_ptr
per esempio) che permette trasferimento della proprietà della memoria - e per una buona ragione, quindi mi aspetto che ciò non sia possibile.
Capisco anche che se fosse possibile, sarebbe un'operazione pericolosa che dovrebbe essere generalmente evitata, proprio come const_cast
. Ma un uso attento in casi come questo sembra più vantaggioso del copia-incolla.
Edit: aggiunto chiarimenti a ciò che intendo per allocazioni 'extra' e cambiato Storage::aggregate_objects()
-Storage::aggregate_some_objects()
per meglio indicare che l'attuazione di questi metodi è più complessa poi un ciclo di gamma basata - da qui il desiderio di evitare la copia -spedizione dell'attuazione.
Le funzioni restituiscono per valore, quindi allocare un nuovo vettore ogni volta. Quali "allocazioni extra" stai cercando di evitare? –
Sì, le funzioni restituiscono in base al valore, il che significa che deve verificarsi almeno un'allocazione dell'heap (caso migliore: conosco la dimensione del vettore restituito e posso chiamare 'vector :: reserve'). Sto parlando di allocazioni che si svolgeranno nella più semplice implementazione dei metodi in questione che non coinvolge il copia-incolla: la versione non-'const' chiama la versione 'const' (che restituisce' std :: vector') e popola un separato 'std :: vector '. La creazione di un vettore separato comporterà almeno un'altra assegnazione ("extra") che vorrei evitare. Chiarito questo nella domanda. –
Se l'obiettivo è semplicemente di evitare la duplicazione del corpo della funzione, allora non provare a fare qualcosa di stupido con calchi e comportamento indefinito, basta scrivere un modello di funzione che restituisce 'std :: vector' e quindi invocarlo con 'T' = = 'Oggetto' o con' T' == 'const Object'. –