C++面向对象编程 (12)

许多库的供应商提供辅助类,用于帮助达到线程安全。例如,查看提供线程安全引用计数的类十分常见。如果你的项目需要线程安全,它可能会帮助实现一组确保线程安全的低级类。这样的类可以提供引用计数、线程安全指针、线程安全打印实用程序等。如果整个项目小组都在各自的实现中使用这些类,就能保证整个项目的线程安全。

断言和不变式

断言(assertion)是一个用于评估真假的表达式。如果表达式评估为假,则断言失败。
每个类都会在对象中包含一些恒为真的条件,无论对象调用任何成员函数,这些条件都必须为真。这样的条件称为类不变式(class invariant)。类不变式就是在对象的生命期内,必须保证对象状态的语句。
在进入和退出每个操作(成员函数)时,都必须检查类不变式。

其他 new/delete

指针真正的用武之地在于,在运行阶段分配未命名的内存以存储值。在这种情况下,只能通过指针来访问内存。在C++中可以使用new操作符来实现。

Test* pTest = new Test()

程序员需要告诉new需要分配多大的空间,即数据类型Test,然后new去自动寻找Test大小的内存,并返回内存首地址。
pTest指针获取了内存首地址,又知道内存大小(Test),所以就可以锁定数据了。

new的好处是:1.主动管理变量的生命周期;2.运行时申请内存。即动态分配和手动管理内存。

因此使用new的场景有:
1.创建动态数组;
2.对于大型数据类型(一般为自定义类型和字符串),在静态存储区上分配内存。

通常,对于大型数据(如数组、字符串和结构),应使用new,这正是new的用武之地。例如,假设要编写一个程序,它是否需要数组取决于运行时用户提供的信息。如果通过声明来创建数组,则在程序被编译时将为它分配内存空间。不管程序最终是否使用数组,数组都在那里,它占用了内存。在编译时给数组分配内存被称为静态联编(static binding),意味着数组是在编译时加入到程序中的。
但使用new时,如果在运行阶段需要数组,则创建它;如果不需要,则不创建。还可以在程序运行时选择数组的长度。这被称为动态联编(dynamic binding),意味着数组是在程序运行时创建的。这种数组叫作动态数组(dynamic array)。

main.cpp

#include<iostream> #include<cstring> using namespace std; char* getname(const char*); int main() { char* name; name=getname("Boss Chen"); //pn与name共享内存地址,但函数退出后,pn会被销毁,所以只有name在管理内存,因此需要detele[] name cout<<"you entered:"<<name<<endl; delete[] name; return 0; } char* getname(const char* s) { char* pn = new char[strlen(s)+1]; strcpy(pn,s); return pn; //函数退出后指针pn将被销毁,但其内存是保存在静态存储区,所以内存不会被销毁。 } g++ main.cpp ./a.out you entered:Boss Chen

个人理解:
为什么要delete释放资源呢?
因为在使用内置类型和new时系统把被申请的地址加锁了,这样当有新内存被申请时,编译器才不会去访问被申请过(加锁)的内存,
而如果不使用delete,这块内存将永远不会被搜索到。。。

const成员函数

注意,要同时在成员函数的声明和定义中指明const限定符。
const成员函数到底有什么优点?回顾关于接口和客户的讨论。const成员函数向它的客户保证它运行良好,并告诉客户调用const成员函数没有危险。这将逐渐建立客户的自信,他们对正在使用的软件会更加有信心。

unsigned TIntStack::HowMany() const { // 如果添加_sp = 0; 语句会怎样(仅举个例子) // _sp = 0; return _count; }

上面的代码不会修改对象内的任何数据。它只是读取数据成员_count 的值。我们可以将const成员函数看成只读函数。
如果上面带注释的代码行取消注释,编译器就会发现给成员函数_sp赋值的行为,并立即将其作为错误进行标记,因为我们违反了成员函数的常量性(constantness)(即在const成员函数内改变数据成员)。

如果必须在const成员函数内部修改某些数据,正确的处理方法是:声明这些数据成员时添加前缀mutable限定符(例如,mutable bool _cacheValid)。这样,即使在const成员函数中,也可以修改_cacheValid。

性能改善

避免制作对象的副本。复制对象的开销很大(在内存和CPU时间方面)。

避免创建新对象,设法复用现有对象。创建(和销毁)对象开销很大。

在适当的时候使用const引用形参。

使用const成员函数。

尽可能地使用初始化语义(而非赋值)。

优先使用指针而不是引用作为数据成员。指针允许惰性求值(lazy evaluation),而引用不允许。

避免在默认构造函数中分配存储区。要将分配延迟到访问成员时,通过指针数据成员(pointer data member)可轻松完成。

用指针数据成员而不是引用和值成员。

尽可能地使用引用计数(在其他章节深入讨论)。

通过重新安排表达式和复用对象减少临时对象。

在编写代码的最初阶段中避免使用技巧。

在现实世界中,通常认为任何软件都是以速度作为最终评定的标准。

RTTI运行时类型识别

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjdxx.html