2012-04-22 17 views
6

Una classe contiene std::vector<int*>. Il codice esterno richiede l'accesso in sola lettura a questo vettore, non dovrebbe essere in grado di modificare i contenuti (né i puntatori né i loro contenuti). All'interno della classe, i valori possono cambiamento (ad esempio double_values(), e così la loro memorizzazione come std::vector<const int*> non è possibile.Trattore vettoriale <int*> come vettore <const int*> senza copiare (C++ 0x)

c'è un modo per restituire l'std::vector<int*> come std::vector<const int*> senza fare una copia? Ci si sente come se non ci dovrebbero essere, perché const è semplicemente in funzione al momento della compilazione di dire ciò che può e non può essere modificato

Codice:. (compilare con g++ -std=c++0x)

class ReadOnlyAccess 
{ 
public: 
    ReadOnlyAccess(const std::vector<int*> & int_ptrs_param): 
    int_ptrs(int_ptrs_param) 
    { 
    } 
    const std::vector<int*> & get_int_ptrs() const 
    { 
    return int_ptrs; 
    } 
    std::vector<const int*> safely_get_int_ptrs() const 
    { 
    // will not compile (too bad): 
    // return int_ptrs; 

    // need to copy entire vector 
    std::vector<const int*> result(int_ptrs.size()); 
    for (int k=0; k<int_ptrs.size(); k++) 
     result[k] = int_ptrs[k]; 
    return result; 
    } 
    void double_values() 
    { 
    for (int*p : int_ptrs) 
     *p *= 2; 
    } 
    void print() const 
    { 
    for (const int * p : int_ptrs) 
     std::cout << *p << " "; 
    std::cout << std::endl; 
    } 
private: 
    std::vector<int*> int_ptrs; 
}; 

int main() { 
    ReadOnlyAccess roa(std::vector<int*>{new int(10), new int(20), new int(100)}); 
    std::vector<const int*> safe_int_ptrs = roa.safely_get_int_ptrs(); 
    // does not compile (good) 
    // *safe_int_ptrs[0] = -100000; 
    roa.print(); 

    const std::vector<int*> & int_ptrs = roa.get_int_ptrs(); 
    // changes are made to the internal class values via the accessor! nooooo! 
    *int_ptrs[0] = -100000; 
    roa.print(); 

    return 0; 
} 
+0

possibile duplicato di [vettoriale e const] (http://stackoverflow.com/questions/2102244/vector-and-const) –

+0

vedere http://stackoverflow.com/questions/2868485/cast-vectort-to- vectorconst-t – WeaselFox

+2

@Bo: Questa domanda non risponde a questa domanda, davvero. E WeaselFox 'è irrilevante anche a causa del puntatore indiretto. – Xeo

risposta

4

Retu il vettore implicherà una copia se si desidera mantenere comunque i puntatori const.

Tuttavia, se il tuo obiettivo è fornire un modo per utilizzare i valori senza modificarli o modificarne il contenitore, allora un algoritmo basato sul modello di visitatore potrebbe essere un'ottima soluzione, in particolare ora che possiamo usare espressioni lambda:

#include <vector> 
#include <iostream> 

class Data 
{ 
public: 

    //...whatever needed to fill the values 

    // here we assume that Func is equivalent to std::function< void (int)> or std::function< void (const int&) > and can return anything that will be ignored here. 
    template< class Func > 
    void for_each_value(Func func) const // read-only 
    { 
     for(const int* value : m_values) // implicit conversion 
     { 
      func(*value); // read-only reference (const &), or copy 
      // if func needs to work with the adress of the object, it still can by getting a reference to it and using & to get it's adress 
     } 
    } 


    void print() const 
    { 
     std::cout << "\nData values: \n"; 
     for_each_value([](const int value) { std::cout << " "<< value << '\n'; }); 
    } 

    void count_values() const { return m_values.size(); } 

private: 

    std::vector<int*> m_values; 

}; 



int main() 
{ 
    Data data; 
    // ... whatever needed to fill the data 

    data.print();  

    std::vector<int> modified_values; 
    data.for_each_value([&](int value) { modified_values.push_back(value + 42); }); 

    return 0; 
} 

Se si capisce che, ei diversi modi di utilizzare i valori può essere ridotto a un paio di algoritmi di mezza generici, allora sarà rendere il codice più semplice e permetterà di mantenere i dati all'interno della vostra struttura, invece di esporre è il coraggio.

+0

Sai di 'std :: for_each', giusto? – jalf

+0

Ovviamente. Perché lo chiedi esattamente? Qui std :: for_each usato al di fuori della classe non sarebbe di aiuto in quanto richiederebbe di esporre il vero iteratore contenitore, o fare una copia, che deve essere evitato per domanda. Potrei aver solo sostituito il ciclo in for_each_value con uno std :: for_each, senza alcun beneficio. Il punto della mia risposta è che non c'è copia del contenitore, e qualunque sia l'algoritmo per attraversare, non è necessario esporre il contenuto della classe SE si conosce quale tipo di attraversamento è necessario agli utenti della classe. Ovviamente, se non lo sai, abbraccia YAGNI. – Klaim

+0

Detto questo, alcuni casi richiedono che la classe esponga il contenuto dagli iteratori. Ma non penso sia necessario per la domanda specifica. – Klaim

1

È possibile fornire una vista dei valori const tramite iteratori personalizzati. Un modo semplice sarebbe quella di utilizzare boost::iterator:

#include <boost/iterator/indirect_iterator.hpp> 

class ReadOnlyAccess 
{ 
// ... 
    typedef boost::indirect_iterator<const int* const*, const int> const_val_iter_type; 
    const_val_iter_type cval_begin() { 
     return it_t{const_cast<const int* const*>(&int_ptrs[0])}; 
    } 
} 

int main() { 
    // ... 
    auto x = roa.cval_begin(); 
    std::cout << x[0] <<' ' << x[1] << x[2] <<'\n'; 
    // we can still access the pointers themselves via .base() member function: 
    for (int i=0; i<3; ++i) 
     assert(x.base()[i] == safe_int_ptrs[i]); 
    // the values are read-only, the following does not compile: 
    // x[0] = -1; 
    // **x.base() = -1; 
    // *x.base() = nullptr; 
} 

Se abbiamo usato boost::indirect_iterator<typename std::vector<int*>::const_iterator, const int> per const_val_iter_type, potremmo modificare i valori appuntiti via .base() (ma non direttamente come in esempio x[0] = -1), quindi questa soluzione non è generale.

Problemi correlati