Với một lớp container, chẳng hạn như std::vector
, có hai khái niệm khác nhau của liên tục-Ness: của container (nghĩa là kích thước của nó) và của các phần tử. Dường như std::vector
lẫn lộn hai, như vậy mà mã đơn giản sau đây sẽ không biên dịch:const và không const của container và nội dung của nó
struct A {
A(size_t n) : X(n) {}
int&x(int i) const { return X[i]; } // error: X[i] is non-const.
private:
std::vector<int> X;
};
Lưu ý rằng mặc dù thành viên dữ liệu (ba con trỏ vào bắt đầu & cuối của dữ liệu và cuối cùng của bộ đệm được cấp phát) của std::vector
là không phải được thay đổi bằng một cuộc gọi đến số operator[]
, thành viên này không phải là const
- đây có phải là thiết kế lạ không?
Cũng lưu ý rằng cho con trỏ nguyên, hai khái niệm này của hằng số-Ness được gọn gàng tách ra, như vậy mà tương ứng với mã thô-con trỏ
struct B {
B(size_t n) : X(new int[n]) {}
~B() { delete[] X; }
void resize(size_t n); // non-const
int&x(int i) const { return X[i]; } // fine
private:
int*X;
};
công trình tốt.
Vì vậy, cách chính xác/được đề nghị để giải quyết vấn đề này khi sử dụng std::vector
(không sử dụng mutable
) là gì?
Là một const_cast<>
như trong
int&A::x(int i) const { return const_cast<std::vector<int>&>(X)[i]; }
coi là chấp nhận được (X
được biết đến là phi const
, vì vậy không UB đây)?
EDIT chỉ để tránh nhầm lẫn hơn nữa: Tôi muốn thay đổi các yếu tố, ví dụ: các nội dung của container nhưng không chứa chính nó (kích thước và/hoặc vị trí nhớ).
Dữ liệu của 'std :: vector' có thể được thay đổi bởi lệnh gọi của bạn thành' toán tử [] '. Như bạn đã viết 'A :: X',' a.x (1) ++; 'là hoàn toàn hợp pháp, và sửa đổi nội dung của vectơ. –
@DavidSchwartz * Nội dung * của một véc tơ không phải là dữ liệu * thực tế của nó * (mặc dù bạn có thể kết hợp chúng một cách hợp lý như vậy). Nếu bạn kiểm tra 'std :: vector', nó chỉ có 3 con trỏ làm dữ liệu (bắt đầu và kết thúc dữ liệu và kết thúc của bộ đệm). Những điều này vẫn không thay đổi. – Walter