c++类的常量正确性
Const-correctness for C++ classes
class SomeClass {
public:
void Render() const;
private:
mutable Cache m_some_cache;
};
上面的类是const正确的吗?什么时候我可以安全地说"这个操作不会改变实例的内部状态"?
在上面的例子中,SomeClass是渲染屏幕上的东西。它使用缓存(例如OpenGL缓冲区对象)来更快地处理进一步的调用。内部唯一改变的是缓存对象。我在问自己缓存是否已经属于渲染器的内部状态。
这个例子是非常小的,但在我的实际应用程序中,这条路走了很多类,也就是说,很多渲染()调用涉及,他们中的大多数只做缓存。但有些方法也通过资源加载器加载资源——这里的假设仍然正确吗,即方法可能是const的,即使它查询资源管理器来加载资源?
当我们说"内部状态不改变"时,我们指的是一个纯粹的逻辑的东西。改变m_some_cache
是否改变对象状态是一个逻辑判断。const正确性是一个逻辑问题。因此,如果您认为从用户的角度来看,改变m_some_cache
不会影响对象状态(在逻辑意义上),那么代码是常量正确的。
这样想。这完全有效:
void Type::print_self () const {
std::cout << *this << std::endl;
}
您没有修改对象本身,因此使用const
限定符是完全有效的。这种方法是对std::cout
的修改,但这并不算Type::print_self()
的const
。
也就是说,在我看来,mutable Cache
在术语上是矛盾的,除非您仅将Cache
元素用于Render
中的本地存储。如果您真的将其用作缓存,那么将此元素限定为mutable
似乎有点可疑。将它用作缓存(例如,跨Render
调用而不是在Render
调用中使用),您对编译器和类的用户都撒了谎。
编辑
根据OP的评论,Render
方法确实是print_self()
的图形等价物。对象的"真实"状态(为了构造一个最小的工作示例,可能没有显示)可能不会被渲染修改。将Render
指定为const
方法是正确的做法。如果Cache
数据成员存在的原因是作为减速带,避免每次调用Render
时构造和销毁它的成本,那么将Cache
成员限定为mutable
并没有错(这是为了使Render
保持const
所必需的)。
这个问题是逻辑问题。通常,可变成员不被视为内部状态,而是作为实现工件。因此,类的文档通常应该描述被认为是内部状态的内容,它可以不涉及可变成员。什么时候我可以安全地说"这个操作不会改变实例的内部状态"?
const
只关注对象的内部状态。const
-方法可以合法地改变外部状态。这里我们想到了指针的类比:char * const p
是一个常量指针,但它可以改变指向的值。所以你的例子与资源管理器似乎也是正确的。
正如@ildjarn所观察到的,常量正确性指的是可观察对象,而不是对象的内部状态;这就是为什么mutable
很有用。
然后,如果你实际渲染的东西,那么对象的可观察状态表示屏幕不能合理地const
, IMHO,因为它会打破,如果你后来添加一个检查方法来找出什么是在屏幕上/在帧缓冲区。
如果SomeClass
不代表屏幕,那么我希望Render
接受一个可变引用,比如说,一个Screen
对象作为参数。逻辑上,某些必须更改,即使它不是SomeClass
实例。
要问自己的问题是,"调用Render
函数是否会改变对象的定义状态或未来行为,就用户而言?"
假设你的缓存真的只是一个资源缓存,那么修改缓存可能不会改变功能行为,只是使它更快。因为你的类不能保证它有多慢,所以就调用者而言,这不会改变定义的状态或行为。因此,它是mutable
成员的有效候选,可以通过const
成员函数进行修改。
Const-correctness是关于从外部看到的对象的状态。
如果对成员函数的所有调用继续返回相同的结果,则对象的状态在逻辑上是相同的。
- 代理对象的常量正确性
- std::函数常量正确性未遵循
- C++ 常量正确性/缺少支持常量和非常量实例的类的常量构造函数
- 自定义引用包装器的常量正确性
- 如果我公开常量和非常量 API,我是否破坏了常量正确性?
- 如何强制实施有关指针数据成员的常量正确性
- 如何在C++的多维地图中实现常量正确性
- 将函数赋值给函数指针,常量参数正确性
- C++ 函数参数或声明中的常量正确性
- 结构初始化中的常量正确性
- 常量正确性编译错误到模板函数中的无效转换错误
- 如何在不违反常量正确性的情况下使用 std::lock_guard
- 非平凡变量的常量正确性
- 常量正确性和成员参考
- 常量正确性和shared_ptr,一个设计问题
- 观察者常量正确性
- 如何跨指针保持常量正确性
- 为了速度牺牲常量正确性可以吗
- file read()常量正确性
- C++NULL指针和常量正确性