只要定义了一个变量而且其类型带有一个构造函数或析构函数。那么程序到达这里时就要承受构造成本,离开时就要承受析构成本。
即使这个变量并未最终被使用,所以要尽量避免这种情况。
方法就是尽可能延后定义变量,尽量定义变量时使用有参构造函数直接一次性弄好,避免无意义的默认构造行为。
例子
void func()
{
std::string shit;
if(...)
{
throw logic_error(...);
}
}
这样如果有异常就没用到变量
改进
void func()
{
if(...)
{
throw logic_error(...);
}
std::string shit;
}
这样就是无意义的默认构造行为,后面再赋值,效果仍不好。
等待真正使用才定义比较好
void func()
{
if(...)
{
throw logic_error(...);
}
std::string shit(realuse);
}
循环怎么办
变量定义在循环外,性能更好,但是变量作用域更大。如果n很大,其实定义在循环内可能会更好。
旧式转型T(t)
新式转型
const_cast<T>();//用来将对象的常量性转除
dynamic_cast<T>();//用来执行安全向下转型,决定某对象是否归属继承体系中的某个类型,这是唯一可能耗费重大运行成本的转型动作
reinterpret_cast<T>();//意图执行低级转型,实际动作取决于编译器,不可移植,比如把int*转为int。
static_cast<T>();//用来强迫隐式转换,例如将non-const对象转为const对象,或将int转为double,或void*转为其他类型
新式转型受欢迎,因为可以快速看到哪些地方转了型,快速排错。
在继承关系中如果要想调用哪个类的方法最好直接指明调用,而不要转型来调用
例如
class Window{
public:
virtual void onResize(){...}
};
class SpecialWindow:public Window{
public:
virtual void onResize(){
static_cast<Windom>(*this).onResize();//这是错误的方式,原因不太懂。
//正确方式如下
Window::onResize();
}
};
总结
意思大概就是:返回数据成员的引用的话,就可以直接操作内部数据了。
引用,指针和迭代器统统都是所谓的handles(号码牌,用来取得某个对象)
总结
避免返回handles(包括引用,指针,迭代器)指向对象内部。遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将
发生虚吊号码牌的可能性降至最低。
copy and swap:为你打算修改的对象做出一份副本,然后在那副本身上做一切必要修改。若有任何动作抛出异常,原对象仍保持未改变状态。所有改变都成功后,再把修改过的副本和原对象进行swap。
总结
总结
如果使用object references或object pointers可以完成任务,就不要使用objects。
如果能够,尽量以class声明式替换class定义式。
程序库头文件应该以完全且仅有声明式的形式存在。