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_ptr是C++标准库提供的类模板,它帮助程序员管理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;
此时p1和p2都指向同一个对象,我们必须保证将delete表达式应用且只应用在
其中一个指针上面,即要么delete p1; 要么delete p2; 不能两个指针都delete,也
不能都不delete。这是普通指针的又个问题。
int * p1 = new int(1024);
int * p2 = new int(2048);
p2 = p1;
此时p1和p2都指向对象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。
一个命名空间可以有多个别名,而且这多个别名可以交叉使用。
- C++ Primier读后感 之 第八章 域和生命期
- C++ Primier读后感 之 第四章 表达式
- C++ Primier读后感 之 第五章 语句
- C++ Primier读后感 之 第七章 函数
- 第八章 域与生命期
- C++ Primier读后感 之 第三章 C++数据类型
- 域和生命期之总结(第8章)
- 第8章 域和生命期(c++ primer)
- 《构建之法》第八十六章读后感
- 构建之法第八,十六章读后感
- 域和生命期3_对象
- C Primier Plus 第4章 字符串和格式化的输入/输出
- C Primier Plus 第5章 运算符、表达式和语句
- C++primier总结
- 关于《构建之法》第八章的读后感
- 域和生命期1_函数声明与定义
- 域和生命期2_头文件
- 变量(对象)“生命期”和“作用域”的关系
- 编程新感悟
- C#的内存管理:堆栈、托管堆与指针
- UVa 10790 How Many Points of Intersection?
- 直逼 Flash 的流畅感:jQuery 运动特效展示
- ASP.NET安全问题
- C++ Primier读后感 之 第八章 域和生命期
- GridView中,在ItemTemplate下使用button与后台交互
- QtCore学习
- magento -- 新闻插件改造实录一
- 积极参与深化医药卫生体制改革扎实推进中医药事业科学发展——在2010年全国中医药工作会议上的工作报告
- 一道c面试题
- Log4j 简单用法
- sed 指定行插入和替换
- 在Django数据库中添加具有初始值的字段