C++ Primier读后感 之 第八章 域和生命期

来源:互联网 发布:枫叶之国加拿大 知乎 编辑:程序博客网 时间:2024/06/10 09:39

第八章:

1. 变量的声明

extern int obj;     声明一个已经定义的对象obj,此时编译器不分配空间。

extern int obj = 0;     定义了一个obj对象,同时初始化为0,编译器要分配空间。

 

2. C++头文件

C++中头文件是所有extern对象声明,函数声明,inline函数定义和const

量定义的一个集中的位置。

头文件提供了 两个安全保障:

(1) 保证所有文件都包含在同一个全局对象或函数的同一份声明。

(2) 如果需要修改声明,只需要修改一个头文件。

在使用头文件时要注意两点:

(1) 编译头文件也需要时间,所以如果需要包含的头文件过多,可以采用预编译

头文件的机制。

(2) 头文件中不应该出现非const对象的定义,非inline函数的定义。

 

3. C++头文件中变量和函数的定义

C++头文件中能够出现inline函数和const对象的定义的原因是,在程序编译

期间,对于inline函数和const对象有可能会出现常量折叠。

这就要求在编译期间,编译器就可以找到函数或变量的定义,而不是等到链接时,

才去找函数和变量的定义。

 

4. delete语句

delete语句后面的指针可以为0,因为delete语句本身会检查释放的指针是否为0,因此在使用此语句时,不需要人工去判断将要删除的指针是否有效。

if(p != 0)  delete p;     程序中没有必要这样做

delete p;     这个语句和上面两个语句等价,相反上面两个语句还会造成测试语句执行了两次。

执行了delete语句后,p所指向的对象的内存被释放了,但是p的值并没有发生

改变,此时p指向一个无效的地址,p此时被称为空悬指针。为了避免空悬指针

的出现,一般在delete语句后p需要被设置为0

delete p;  p = 0;     设置为0,防止出现空悬指针。

 

5. auto_ptr

auto_ptrC++标准库提供的类模板,它帮助程序员管理new表达式动态分配的

单个对象(auto_ptr无法管理用new表达式分配的数组)

(1) 使用auto_ptr必须首先包含头文件:#include <memory>

(2) auto_ptr有三种构造函数

auto_ptr<int> pi(new int (1024));     new表达式返回的地址来构造

auto_ptr<int> pi2(pi);     用一个auto_ptr对象来构造

auto_ptr<int> pi3;     构造一个空的对象

int m = *pi;     下面使用pi和使用new表达式返回的地址指针一摸一样。

 

 

(3) 定义了auto_ptr对象后,其使用方式和普通指针一样。

int m = *pi;     获取指针所指向的对象的值

(4) auto_ptr对象在撤销时会自动释放其拥有所有权的对象。

(5) auto_ptr和普通指针相比有以下好处。

普通指针的例子:

int * p1 = new int(1024);

此时p1指向对象1024,我们必须保证在p1指针撤销之前的某个地方delete p1;

被调用,以免出现内存泄露个问题。

int * p1 = new int(1024);

int * p2 = p1;

此时p1p2都指向同一个对象,我们必须保证将delete表达式应用且只应用在

其中一个指针上面,即要么delete p1; 要么delete p2; 不能两个指针都delete,也

不能都不delete。这是普通指针的又个问题。

int * p1 = new int(1024);

int * p2 = new int(2048);

p2 = p1;

此时p1p2都指向对象1024,而对象2048成为无法释放的对象,这种对象的

地址称为野地址。这是普通指针的另外一个问题。

 

auto_ptr指针的例子:

auto_ptr<int> p1(new int(1024));

auto_ptr<int> p2(new int(2048));

p2 = p1;

上面的赋值语句执行后,会发生以下事情:

整形对象2048会被删除掉,然后p2指向对象1024,同时p1还丧失了对象的1024

的所有权,p1拥有了1024的所有权。

这意味着:

auto_ptr指针拥有所有权的对象会在指针撤销时自动被释放。

当两个auto_ptr指针指向同一个地址时,先指向的指针会自动释放其对地址的所

有权,这样就保证了一个地址不会被释放两次。

当一个auto_ptr指针被初始化或赋值时,如果这个指针原来就拥有一个地址,那

么操作后,原来拥有的地址就会被删除掉,这样就避免了也指针的出现。

(6) get()

auto_ptr对象的get方法可以返回其内部的底层指针。

int * p = p1.get();     int型的auto_ptr对象返回一个int型指针。

(7) reset()

atuo_ptr对象的reset方法可以重置其内部指针

auto_ptr<int> p1;     p1不指向任何地址

p1.reset(new int(1024));     利用此函数将对象指向1024对象

p1 = new int(1024);     错误,不支持指针直接赋值

p1.reset(new int(2048));     将对象指向2048对象

说明:在调用此函数之前,如果auto_ptr对象已经拥有一个地址,那么调用时,

原来拥有的那个地址会被删除,然后再指向新的地址。

(8) 使用auto_ptr对象应该注意的问题:

不能用一个指向内存不是通过应用new表达式分配的指针来初始化或赋值

auto_ptr对象。

int m;

auto_ptr p(&m);     错误,地址&m不是通过new表达式得到的。

 

不能让两个auto_ptr对象拥有同一个地址。虽然auto_ptr类的设计者竭力避免这

种情况的发生,但是还有这种情况出现的可能。

int * p = new int(2048);

auto_ptr<int> p1(p);

auto_ptr<int> p2(p);

此时两个auto_ptr对象都指向同一个地址,这会引发错误。

auto_ptr<int> p1(new int(2048));

auto_ptr<int> p2(p1.get());

此时两个auto_ptr对象也会指向同一个地址。

使用类中的release方法可以避免这个问题。

auto_ptr<int> p1(new int(2048));

auto_ptr<int> p2(p1.release());

此时会首先释放p1对对象2048的所有权,然后返回对象2048的地址来初始化

p1

 

6. 动态分配数组

动态分配数组的好处是,数组的第一维不必是常量。

动态分配数组,只有第一维可以用运行时刻计算的表达式来指定,其他维必须是在编译时刻已知的常量值。

 

7. 动态分配常量

可以用new表达式动态分配一个常量,但是要满足两个条件:

(1) const对象必须被初始化

(2) new表达式返回的指针是一个指向常量的指针

const int * pi = new const int(2048);

pi无法改变所指向的地址的值,其对象内存同样用delete来释放。

无法分配一个常量数组,因为动态分配数组时,无法同时给数组元素赋值。

 

8. 定位new

int * buf = new int[1024];     预留内存

int * p = new (buf) int;     buf中创建一个对象

delete buf;     删除预留内存

注意:定位new的返回值,不能用delete表达式来删除,因为定义new并没有分配空间,我们只需要在最后释放预留的那段内存。

 

9. 名字空间

(1) 名字空间可以是非连续的。当定义一个名字空间时,如果前面已经定义了这个名字空间,则会打开前面的名字空间,将下面的定义加到原来的名字空间里面。如果前面没有定义,则定义一个新的名字空间。

(2) 同一程序中的不同文本的命名空间也是可以积累的。

(3) 名字空间中的成员是不隐藏在名字空间中的。

(4) 要将一个全局函数或全局变量限制在当前文件可见,有两种办法:

在标准C++之前,可以定义静态全局函数和静态全局变量,定义后全局的函数和变量都只能在当前文件中可见。

在标准C++中,可以把全局函数或变量放入一个不具名的命名空间中,这样全局函数和变量就只在当前文件中有效。

// file1.cpp

{

void swap(){}

}

// file1.cpp中可以直接访问swap函数,而且swap函数在其他文件中是无法访问的。

注意:这里不能把swap放入具名的命名空间中,因为如果swap在具名的命名空间中,虽然在其他文件中无法访问swap,但是在file1.cpp中访问swap时,也必须要带上命名空间的名称才可以正常访问。

(5) 命名空间可以取别名

namespace mlib = cplusplus_primer::MatriLib;

在下面的程序可以用mlib来代替cplusplus_primer::MatriLib

一个命名空间可以有多个别名,而且这多个别名可以交叉使用。

原创粉丝点击