Tôi viết một lớp CustomVector, nội bộ lưu trữ dữ liệu sử dụng một vector tiêu chuẩn:C++ Viết const vector với con trỏ để không const
template <class T>
class CustomVector {
friend class CustomVector_ref<T>;
public:
...
private:
std::vector<T> _data;
};
Sau đó, để trích xuất subvectors từ CustomVector, tôi sử dụng một lớp lưu trữ con trỏ cho mỗi phần tử dữ liệu:
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;
};
Bây giờ, để minh họa cho vấn đề của tôi nó là đủ để xem xét các costructor đơn giản xây dựng một tài liệu tham khảo cho tất cả các yếu tố của CustomVector
template<class T>
CustomVector_ref<T>::CustomVector_ref(CustomVector<T>& cv)
{
for (T& el : cv._data)
_data_ref.push_back(&el);
}
đó làm việc tốt, nhưng nếu tôi có một CustomVector const, tôi cũng cần phải xác định các nhà xây dựng:
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));
}
đó làm việc quá, nhưng nếu đối tượng CustomVector_ref không khai báo là const, sau đó với các phi -const operator [] có thể ghi dữ liệu vào đối tượng CustomVector const.
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
Có thể tránh hành vi này?
tôi đã nhận thấy rằng điều này cũng xảy ra với vectơ tiêu chuẩn, ví dụ
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
Vì vậy, vì đây là tiêu chuẩn C++, tôi không bận tâm quá nhiều để sửa chữa CustomVector của tôi, nhưng nó sẽ được tốt đẹp để biết nếu có một giải pháp (không quá phức tạp).
Bạn cần suy nghĩ về thực tế đơn giản rằng các thùng chứa thư viện chuẩn xác định hai lớp lặp khác nhau: 'iterator' và' const_iterator'. Có một lý do chính đáng cho điều đó, và bạn vừa phát hiện ra lý do đó là gì. Tình hình của bạn là hoàn toàn tương tự. Bạn cần triển khai hai tham chiếu khác nhau, một tham chiếu có thể thay đổi và 'const'. Đối với tín dụng bổ sung, tham chiếu có thể thay đổi sẽ được chuyển thành tham chiếu 'const', vì vậy nó có thể được chuyển đến các hàm lấy tham chiếu' const' làm đối số. –
do dự để gắn cờ nó là lừa đảo, nhưng điều này được thực hiện chặt chẽ https://stackoverflow.com/questions/44882363/does-const-iterator-really-need-to-be-a-different-class-than-iterator – user463035818
Điều gì về việc sử dụng 'CustomVector_ref'?Không có const_cast cần thiết theo cách này –
geza