2017-07-07 4 views
10

Ich bin ein CustomVector Klasse Schreiben intern Speichern von Daten eines Standard-Vektor unter Verwendung von:C++ Writing const Vektoren mit Zeigern auf non const

template <class T> 
class CustomVector { 
    friend class CustomVector_ref<T>; 

    public: 
    ... 

    private: 
    std::vector<T> _data; 
}; 

Dann wird, um Subvektoren von CustomVector zu extrahieren, verwende ich eine Klasse Speichern von Zeigern auf jedes Element der Daten:

template <class T> 
class CustomVector_ref { 
    public: 
    //Returns the value stored in CustomVector 
    //and pointed-to by _data_ref 
    T& operator[] (size_t id) { return *_data_ref[id] } 
    const T& operator[] const (size_t id) { return *_data_ref[id] } 
    ... 
    private: 
    std::vector<T*> _data_ref; 
}; 

, Jetzt ist mein Problem zu veranschaulichen, genügt die einfache costructor Aufbau eines Verweises auf alle Elemente der CustomVector

zu berücksichtigen

Das funktioniert gut, aber wenn ich ein const CustomVector haben, ich brauche auch den Konstruktor zu definieren:

template<class T> 
CustomVector_ref<T>::CustomVector_ref(const CustomVector<T>& cv) 
{ 
    for (const T& el : cv._data) 
    _data_ref.push_back(const_cast<T*>(&el)); 
} 

Das funktioniert auch, aber wenn das CustomVector_ref Objekt nicht als const deklariert, dann mit dem nicht -const operator [] Es ist möglich, Daten in das const CustomVector-Objekt zu schreiben.

const CustomVector<int> cv(...) //CostumVector is somehow constructed, 
           //that does not matter now 

std::cout<<cv[0]<<std::endl; //output 1 for example 

CustomVector_ref<int> cvr(cv) 

cvr[0] = 2; 

std::cout<<cv[0]<<std::endl; //now cv[0] stores 2 

Es ist möglich, dieses Verhalten zu vermeiden?

Ich habe bemerkt, dass dies geschieht auch mit Standardvektoren, beispielsweise

const std::vector<int> v(1,1); 
std::vector<int*> vp; 

vp.push_back(const_cast<int*>(&v[0])); 

*vp[0] = 2; 

std::cout<<v[0]<<std::endl; // now v[0] stores 2, not 1 

Also, da dieser Standard C++, ich Mühe zu viel nicht meinen CustomVector zu beheben, aber es wäre schön zu wissen wenn es eine (nicht zu gewundene) Lösung gibt.

+18

Sie müssen über die einfache Tatsache nachdenken, dass Standardbibliothekscontainer zwei verschiedene Iteratorklassen definieren: 'iterator' und' const_iterator'. Es gibt einen guten Grund dafür, und Sie haben gerade herausgefunden, was dieser Grund ist. Ihre Situation ist völlig analog. Sie müssen zwei verschiedene Referenzen implementieren, eine veränderbare und eine "konstante" Referenz. Für eine zusätzliche Gutschrift sollte die veränderbare Referenz auf die Referenz "const" umsetzbar sein, sodass sie an Funktionen übergeben werden kann, die "konstante" Referenzen als Argumente verwenden. –

+0

Zögern, es als dupe zu kennzeichnen, aber das ist eng reeted https://stackoverflow.com/questions/44882363/does-const-iterator-really-need-to-be-a-different-class-than-iterator – user463035818

+1

Was über die Verwendung von 'CustomVector_ref '?Kein const_cast benötigt so – geza

Antwort

1

Ich bin nicht genau sicher, was Sie versuchen zu tun. Versuchen Sie, die Änderung des ursprünglichen Vektors zu verhindern, unabhängig davon, ob CustomVector_ref mit einer const oder non-const Version des Vektors initialisiert wurde? Wenn ja, können Sie dies tun, indem Sie einfach den Rückgabetyp von operator[] ändern, wie folgt:

template <class T> 
class CustomVector_ref { 
    public: 
    ... 
    const T& operator[] (size_t id) { return *_data_ref[id] } 
    const T& operator[] const (size_t id) { return *_data_ref[id] } 
    ... 
}; 

Beachten Sie, dass Zeiger in den ursprünglichen Vektor-Speicherung gefährlich ist. Wenn sich die Größe des ursprünglichen Vektors ändert, werden möglicherweise alle Zeigerwerte ungültig gemacht.

Wenn Sie das Verhalten von CustomVector_ref je nach ändern mögen, ob es mit einer const oder non-const Version des Original-Vektor konstruiert ist, müssen Sie die Signatur der Vorlage ändern, um zwischen const zu differenzieren zu können und non-const Versionen des ursprünglichen Vektors. Eine Beispielimplementierung:

#include <iostream> 
#include <vector> 

template <class T> 
class CustomVector_ref { 
public: 
    CustomVector_ref(T& orig_vector) : m_vector_ref(orig_vector) {} 

    auto& operator[] (size_t id) { return m_vector_ref[id]; } 
    const typename T::value_type& operator[] (size_t id) const { return m_vector_ref[id]; } 

    private: 
    T& m_vector_ref; 
}; 

int main(int argc, char* argv[]) { 
    std::vector<int> my_vec({1, 2, 3}); 
    std::cout << my_vec[0] << std::endl; 

    CustomVector_ref<std::vector<int>> cv_ref(my_vec); 
    cv_ref[0] = 2; // Assignment is ok; non-const cv_ref initialized with a non-const vector 
    std::cout << cv_ref[0] << std::endl; //now cv[0] stores 2 

    CustomVector_ref<const std::vector<int>> cv_cref(my_vec); 
    // cv_cref[0] = 2; // Compile error: assignment of read-only location 
    const_cast<int&>(cv_cref[0]) = 2; // Explicit override of const 
    std::cout << cv_cref[0] << std::endl; 

    const std::vector<int> my_const_vec({1, 2, 3}); 
    // CustomVector_ref<std::vector<int>> cv_cref2(my_const_vec); // Compile error; non-const initialization from const 
    CustomVector_ref<const std::vector<int>> cv_cref3(my_const_vec); // Ok, const initialization from const 
    // cv_cref3[0] = 2; // Compile error: assignment of read-only location 
    const_cast<int&>(cv_cref3[0]) = 2; // Explicit override of const 
    std::cout << cv_cref3[0] << std::endl; 

    return 0; 
} 
Verwandte Themen