将成员函数标记为 const 时,如果它在概念上不是
Mark a member function as const when it is conceptually not
据我在这里和那里阅读,const
应该尽可能使用。但是,我有一个案例总是困扰着我。
当成员函数不更改任何成员变量值但在概念上不是const
函数时,我是否应该将成员函数标记为const
?
例如:
class Engine{
public:
int status;
};
class Car{
public:
void start() const{
engine_->status = 1;
}
private:
std::unique_ptr<Engine> engine_;
};
编译器将接受start()
的恒定性,因为engine_
作为指针没有改变。然而,至少 IMO 似乎很不现实,在一个名为Car
的类中名为start
的函数是一个const
函数!
这个例子只是一个快速的例子。通常,Car
类的某些内部状态应相应地更新const
使得关键字不可行。然而,这个迷你例子只是为了说明我的想法。
函数是否应该const
的一个简单指标是:
Type a{...};
Type b{...};
bool comp1 = a == b;
b.some_func(...);
bool comp2 = a == b;
如果comp1
和comp2
可以不同,那么some_func
就不const
了。
显然,并非每种类型都有operator==
重载,但大多数类型至少具有要测试以查看它们是否相等的概念。具有不同engine
状态的不同Car
实例是不相等的。因此,更改engine
状态的函数不是const
。
在您的情况下,编译器允许您由于通过指针不完全传播恒常性而使 conststart()
。如果将指针替换为类型为Engine
的对象,则问题将消失。所以答案是否定的,在这种情况下不应该const
,因为使用Engine
作为智能指针或实例是内部细节,不应该影响类Car
的公共接口。
据我在这里和那里阅读,应该尽可能使用 const。
这种说法过于笼统,与任何通用建议一样,不应在每种情况下都正式使用。
在你的例子中,你可能想要std::experimental::p ropagate_const:
class Car{
public:
void start() { engine_->status = 1; }
private:
std::experimental::propagate_const<std::unique_ptr<Engine>> engine_;
};
那么你的start
就不能再const
了.
const
的含义可能会有所不同。
-
如果它保留
.==
,则const
-
如果您的类型遵循引用语义并且不会更改引用的内容,则某些内容
const
。 -
如果可以以合理的方式在任何右值或左值上使用,则
const
某些东西。
有些 东西是
const
是否可以安全地从多个线程使用。如果编译为
const
,则const
.如果对象声明的内部状态没有被它改变,那么某些东西
const
。
所有这些都是确定方法或参数是否const
的合理规则。
要非常小心的一件事是要知道T const*
和T*const
之间的区别,并且不要意外地将顶级常量作为内部常量。 它不是;tconst iterator
它是const_iterator
. 不是const gsl::span<int>
,而是gsl::span<const int>
。 不是const unique_ptr<T>
,而是unique_ptr<T const>
。
另一方面,vector
是一个值语义类型;它假装它的缓冲区是它的一部分(即使这是一个谎言)。 不是vector<const T>
,而是const vector<T>
。
- 如果可推导类型上有替换,可变参数模板类型推导会使编译器崩溃
- Poco::Net::FTPClientSession 在 open() 方法上挂起 129 秒,如果 ftp 主机不存
- 如果我在 const 函数上使用指针,我可以返回什么?
- 如果变量数据包含大于 vector 所有元素的整数,则仅在视觉工作室上接收"矢量下标超出范围"?
- 如果我在字符数组上使用 close() 会发生什么?
- 如果类在堆上,函数是转到堆还是堆栈?
- 如果由不同的线程写入 8 字节,那么现代英特尔 x86 上的 8 字节读取是否保证理智?
- 我是否应该在包含虚拟方法的类上使用'memcpy'?如果没有,如何替换它?
- 编译了一个recent-C++.因此,如果没有暴露std符号,请在旧系统上运行
- 如果您在C++上有 Makefile 项目,如何在 VScode 中"fix"调试器?
- 如果在创建对象时创建了 VPTR,那么为什么具有虚拟功能的类的大小在 32 位系统上为 4,在 64 位机器上为 8
- 如何获得GUID编码器,如果我在IMFTransform上有一个指针?
- 如果我在每个平台上使用相同的种子,随机结果会相同吗?
- 如果我在 Linux 上更改C++动态共享库,而我的可执行程序在其上使用,会发生什么
- 是一个容器肯定是概念上的范围
- 将成员函数标记为 const 时,如果它在概念上不是
- 显示最大的数字,如果行上的错误会出现错误
- 概念上的混乱
- 复制列表初始化是否在概念上调用复制 ctor
- 是否有任何技术/概念上的原因boost::circular_buffer不支持移动赛门铁克?