如前所述自表达式”不容变”的优点,在他们的程式结构设计实践中,假如恰当采用C++中的自表达式,对提高流程的时效性和易用性都有非常大的协助。
自表达式原则的关键点:
尽量采用const表达式尽量采用const核心理念成员表达式 尽量传达const操作符和const提及尽量采用constexpr1:尽量采用const表达式
不容变第一类更容易逻辑推理,因而多于在须要更动其值时才将第一类增设为非const。避免碰巧的或无法特别注意到的值变动。比如说常用的for循环式:
for (const int i : c) cout << i << \n; // just reading: const
for (int i : c) cout << i << \n; // BAD: just reading
或者表达式返回值:
void fun()
{
int i =0;
const int bound = 1000; // bound 不能被不幸修正。
for(int i=0;i<bound;i++)
{
…
}
}
个别情况
透过值传达的表达式参数极少发生发生改变,但也极少新闻稿为const。
void f(const char* p); // 有必要性,*p 是自表达式
void f(char * const p); // 没必要性
void g(const int i) { … } // 没必要性
特别注意,表达式参数是两个返回值,因而对它的更动是返回值2: 尽量采用const核心理念成员表达式
核心理念成员表达式假如被记号为const,假如它发生改变了第一类的状况。这种能更准确地表明结构设计企图、更快的时效性、C++能捕捉更多严重错误,有时候还能提供更多更多的强化良机。
先看两个严重错误实例:
class Point {
int x, y;
public:
int getx() { return x; } // BAD, should be const as it doesnt modify the objects state
// …
};
void f(const Point& pt)
{
int x = pt.getx(); // ERROR, doesnt compile because getx was not marked const
}
将f表达式的参数去掉const,当然能解决上面的编译问题。但多于当被调用的表达式会修正第一类时,才假如这种做。代码的读者也会假设接受 非const T*或T&的表达式将修正所提及的第一类。即使现在没,那么以后可能会这种做。
特别注意:
有些代码/库可能并未遵守const原则。它可能提供更多了新闻稿T* t的表达式,即使这些表达式不能修正t。你能
更新库代码,恰当采用const–首选的长期解决方案透过const_cast抛弃const–最好避免提供更多包装表达式void f(int* p); // old code: f() does not modify `*p`
void f(const int* p) { f(const_cast<int*>(p)); } // wrapper
请特别注意,这个包装表达式解决方案是两个补丁,假如只在f()的新闻稿不能直接修正时采用。特别注意:
const核心理念成员表达式能:
修正mutable核心理念成员 调用操作符第一类(或者智能操作符)的非const核心理念成员表达式class DateNotifier
{
DataNotifier():notifyCnt(0){}
public:
void notify()
{
++notifyCnt;
}
public:
int notifyCnt;
};
class Date {
public:
Data():dn(new DateNotifier()),udn(make_unique<DateNotifier>()){}
~Data(){delete dn;}
const string& string_ref() const
{
if (string_val == “”) compute_string_rep();
dn->notify(); //能调用df的非const成员表达式
udn->notify(); //能透过智能操作符调用非const核心理念成员表达式
return string_val;
}
// …
private:
void compute_string_rep() const // compute string representation and place it in string_val
{
string_val = “2022/01/14”;
}
mutable string string_val; //mutable核心理念成员,能修正
DateNotifier * dn;
unique_ptr<DateNotifier > udn;
// …
};
3:尽量传达const操作符和const提及
在结构设计表达式参数的时候,const 参数不仅能避免其被不幸更动,也能暗示该表达式不能更动该参数。
值传达的参数不须要const(见上)void f(char* p); // does f modify *p? (assume it does)
void g(const char* p); // g does not modify *p
传达指向非const第一类的操作符或提及本身并不是坏事,但多于当被调用的表达式假如修正第一类时,才假如这种做。4: 尽量采用constexpr
constexpr是c++11新增关键字。它与const的根本区别是:
const — 运行期确定的自表达式
constexpr — C++确定的自表达式
constexpr带来的好处是:更快的性能,更快的编译时检查,有保证的编译时计算,没竞争条件的可能性
例:
double x = f(); // possible run-time evaluation
const double y = f(); // possible run-time evaluation
constexpr double z = f(); // error unless f(2) can be evaluated at compile time
假如还是不理解运行期和C++的区别,这种思考:f() 假如是返回实时系统时间,那么返回值一定是运行期才能确定的。f()假如是返回圆周率,那么显然其返回值编译期就是能确定的。参考:
CppCoreGuidelines/CppCoreGuidelines.md at master · isocpp/CppCoreGuidelines