2015-10-14 5 views
9

Dire che ho questa classe:metodo const in una classe di ritorno vettore di puntatori

#include <vector> 
using namespace std; 

class Bag 
{ 
    vector<int*> items; 

public: 
    void addItem(int* i) 
    { 
     items.push_back(i); 
    } 
    const vector<int*> getItems() const 
    { 
     return items; 
    } 
}; 

Il problema è che voglio evitare modifiche dei valori puntato dal puntatori in voci dei parametri. Ma usando il vettore di ritorno da getItems mi è permesso modificare i valori puntati.

Ora, per risolvere il problema posso dichiarare le voci parametro come vector<const int*> ma non posso modificare i valori nella mia classe. Esiste un altro modo per proteggere i valori ma non usare ancora const nelle dichiarazioni degli articoli?

+7

'std :: vector getItems() const {return std :: vector (items.begin(), items.end()); } ' –

+0

@KerrekSB questa dovrebbe essere una risposta. –

+0

@ KerrekSB Grazie per la risposta, ma è l'unico modo? Mi sembra di creare una copia inefficiente anche se creo una copia devo restituire per valore vero? inoltre, cosa ne pensi della prima domanda? – Adam

risposta

6

Come @KerrekSB ha sottolineato, è necessario ricostruire la struttura, cambiando il tipo di dell'elemento ad un const uno:

std::vector<const int*> getItems() const { 
    return std::vector<const int*>(items.begin(), items.end()); 
} 

Qui il costruttore vector<const int*> utilizza la conversione implicita da int* a const int*. Non puoi semplicemente restituire items qui, perché vector<T> è invariant su T. Questo significa direttamente che non c'è modo di convertire da vector<int*> a vector<const int*> solo da un cast di tipo.


Per affrontare il tuo commento:

È questo l'unico modo? Mi sento come se creare una copia fosse inefficiente.

Come per la copia, copia solo i dati del puntatore, in genere 8 byte per elemento. Per un vettore di puntatori a strutture più grandi, è in genere trascurabile, ma per un vettore di int s è davvero un overhead piuttosto grande.

Il che ci porta alla domanda: perché memorizzi i puntatori in primo luogo? È sufficiente memorizzare vector<int> e quindi è sufficiente restituire un const& ad esso.

+0

Attenti a quei puntatori, quando la "borsa" si spegne, penzoleranno. 'shared_ptr' è molto meglio ed evita tutti i puntatori ancora di più. – edmz

+0

Il motivo per cui stavo usando i puntatori è perché volevo in seguito utilizzare gli oggetti che non hanno il codice c'tor – Adam

+2

predefinito può essere restituito {items.begin(), items.end()}; ' – Jarod42

5

Se si vuole evitare copie e permettere accesso in sola lettura ai vostri std::vector elementi, si potrebbe invece fornire funzioni per ottenere un const_iterator nel contenitore:

class Bag 
{ 
    vector<int*> items; 

public: 
    void addItem(int* i) 
    { 
     items.push_back(i); 
    } 

    //could just be called begin if that gives the correct idea 
    vector<int*>::const_iterator itemsBegin() const 
    { 
     return std::cbegin(items); 
    } 

    vector<int*>::const_iterator itemsEnd() const 
    { 
     return std::cend(items); 
    } 
}; 

Poi si sarebbe ciclo nel corso degli Bag contenuti utilizzando quell'iteratore piuttosto che ottenere un intero vector di elementi. Se hai fornito le funzioni begin e end, potresti persino utilizzare i for-loops basati su intervallo.

+1

Oppure, in C++ Successivo, sarebbe semplicemente un intervallo. –

+0

@BartekBanachewicz per favore, spiega. –

+1

@VictorPolevoy probabilmente si riferisce a questa [biblioteca della gamma] (https://github.com/ericniebler/range-v3) e alla [proposta standard associata] (http://www.open-std.org/jtc1/sc22/ WG21/docs/documenti/2015/n4382.pdf). – TartanLlama