Wal*_*ter 12 c++ containers const
对于容器类,例如std::vector,有两个不同的常量概念:容器的概念(即它的大小)和元素的概念.似乎std::vector混淆了这两个,这样下面的简单代码就不会编译:
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;
};
Run Code Online (Sandbox Code Playgroud)
需要注意的是,即使数据成员(三个指针指向数据的开始和结束,所分配的缓冲区的结束)std::vector都没有通过其呼叫改变operator[],这件是不是const-是不是这样一个奇怪的设计?
还要注意,对于原始指针,这两个常量概念是完全分开的,这样相应的原始指针代码
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;
};
Run Code Online (Sandbox Code Playgroud)
工作得很好.
那么使用std::vector(不使用mutable)时处理这个问题的正确/推荐方法是什么?
是一个const_cast<>如此
int&A::x(int i) const { return const_cast<std::vector<int>&>(X)[i]; }
Run Code Online (Sandbox Code Playgroud)
被认为是可接受的(X已知是非const,所以这里没有UB)?
编辑只是为了防止进一步的混淆:我确实想要修改元素,即容器的内容,而不是容器本身(大小和/或内存位置).
Jam*_*nze 18
C++只支持一个级别const.就编译器而言,它是按位const:实际在对象中的"位"(即计入sizeof)不能在没有玩游戏(const_cast等等)的情况下进行修改,但其他任何东西都是公平的游戏.在C++的早期(20世纪80年代末,90年代初),关于按位const与逻辑const(也称为Humpty-Dumpty const)的设计优势进行了大量讨论,因为正如Andy Koenig曾告诉我的那样,程序员使用
const,这意味着程序员想要它的意思.最终的共识有利于逻辑const.
这确实意味着容器类的作者必须做出选择.容器的元素是否是容器的一部分.如果它们是容器的一部分,那么如果容器是const,则不能修改它们.没有办法提供选择; 容器的作者必须选择其中一个.这里也似乎有一个共识:元素是容器的一部分,如果容器是const,则不能修改它们.(也许与C风格数组的并行在这里起作用;如果C风格数组是const,那么你就不能修改它的任何元素.)
和你一样,我曾经遇到过我想要禁止修改向量大小(可能是为了保护迭代器)而不是其元素的时候.没有真正令人满意的解决方案; 我能想到的最好的方法是创建一个包含a的新类型,mutable std::vector并提供与const
此特定情况下我需要的含义相对应的转发函数.如果你想区分三个级别(完全const,部分const和非const),你需要派生.基类只暴露完全const和部分const函数(例如a const
int operator[]( size_t index ) const;和int operator[](
size_t index );,但不是void push_back( int );); 允许插入和删除元素的函数仅在派生类中公开.不应插入或删除元素的客户端仅传递给基类的非const引用.
| 归档时间: |
|
| 查看次数: |
6145 次 |
| 最近记录: |