30、C++ Primer 4th 笔记,异常处理,auto_ptr类

时间:2021-12-31 11:52:14

1auto_ptr为标准库提供的“资源分配即初始化”类,是接受一个类型形参的模板,它为动态分配的对象提供异常安全特性。在memory头文件中定义。

2auto_ptr操作

auto_ptr<T> ap;

创建名为 ap 的未绑定的 auto_ptr 对象

auto_ptr<T>

ap(p);

创建名为 ap auto_ptr 对象,ap 拥有指针 p 指向的对象。该构造函数为 explicit

auto_ptr<T> ap1(ap2);

创建名为 ap1 auto_ptr 对象,ap1 保存原来存储在ap2 中的指针。将所有权转给 ap1ap2 成为未绑定的auto_ptr 对象

ap1 = ap2

将所有权 ap2 转给 ap1。删除 ap1 指向的对象并且使 ap1指向 ap2 指向的对象,使 ap2 成为未绑定的

~ap

析构函数。删除 ap 指向的对象

*ap

返回对 ap 所绑定的对象的引用

ap->

返回 ap 保存的指针

ap.reset(p)

如果 p ap 的值不同,则删除 ap 指向的对象并且将 ap绑定到 p

ap.release()

返回 ap 所保存的指针并且使 ap 成为未绑定的

ap.get()

返回 ap 保存的指针

    auto_ptr只能用于管理从new返回的一个对象,它不能管理动态分配的数组。当auto_ptr被复制或赋值的时候,有不寻找的行为,因此不能将auto_ptr存储在标准库容器类中。

3、每个auto_ptr对象绑定到一个对象或者指向一个对象。当auto_ptr对象指向一个对象的时候,可以说它“拥有”该对象。当auto_ptr对象超出作用域或者另外撤销的时候,就自动回收auto_ptr所指向的动态分配对象。

    auto_ptr是可以保存任何类型指针的模板。

示例

void f()
{
	auto_ptr<int> ap(new int(42)); // allocate a new object
	// code that throws an exception that is not caught inside f
}   // auto_ptr freed automatically when function ends

4、注意到,接受指针的构造函数为explicit构造函数,所以必须用初始化的直接形式来创建auto_ptr对象。

示例

// error: constructor that takes a pointer is explicit and can't be used implicitly
auto_ptr<int> pi = new int(1024);
auto_ptr<int> pi(new int(1024)); // ok: uses direct initialization

pi所指的由new表达式创建的对象在超出作用域时自动删除。

5auto_ptr的主要目的是在保证自动删除auto_ptr对象引用的对象的同时,支持普通指针式行为。

示例

auto_ptr<string> ap1(new string("Hellobaby!"));
*ap1 = "TRex"; // assigns a new value to the object to which ap1 points
string s = *ap1; // initializes s as a copy of the object to which ap1 points
if (ap1->empty()) // runs empty on the string to which ap1 points

6auto_ptr对象的赋值和复制是破坏性操作行为,与普通指针的复制和赋值有区别。普通指针赋值或复制后两个指针指向同一对象,而auto_ptr对象复制或赋值后,将基础对象的所有权从原来的auto_ptr对象转给副本,原来的auto_ptr对象重置成为未绑定状态。

    因此,auto_ptr赋值的左右操作数必须是可修改的左值。因为标准库容器要求在复制或赋值后两对象相等,所以auto_ptr不能存储在标准容器中。

7、默认情况下,auto_ptr的内部指针值置为0

8、测试auto_ptr对象

    auto_ptr 类型没有定义到可用作条件的类型的转换,相反,要测试auto_ptr 对象,必须使用它的 get 成员,该成员返回包含在 auto_ptr 对象中的基础指针。

示例

// error: cannot use an auto_ptr as a condition
if (p_auto)
   *p_auto = 1024;
// revised test to guarantee p_auto refers to an object
if (p_auto.get())
   *p_auto = 1024;

    应该只用 get 询问 auto_ptr 对象或者使用返回的指针值,不能用 get 作为创建其他 auto_ptr 对象的实参。

9reset操作

不能直接将一个地址(或其它指针)赋给auto_ptr对象。

示例

#include <iostream>
#include "memory"
using namespace std;

int main()
{
	auto_ptr<int> p_auto(new int(123));
	//p_auto = new int(1024); // error: cannot assign a pointer to an auto_ptr
	if (p_auto.get())
		*p_auto = 1024;
	else
		p_auto.reset(new int(1042));
	return 1;
}

    正如自身赋值是没有效果的一样,如果调用该 auto_ptr 对象已经保存的同一指针的 reset 函数,也没有效果,不会删除对象。

10、正确使用auto_ptr类,有如下限制:

1)不要使用auto_ptr对象保存指向静态分配对象的指针,否则,当auto_ptr对象本身被撤销的时候,它将试图删除指向非动态分配对象的指针,导致未定义的行为。

2)永远不要使用两个 auto_ptrs 对象指向同一对象,导致这个错误的一种明显方式是,使用同一指针来初始化或者 reset 两个不同的 auto_ptr 对象。另一种导致这个错误的微妙方式可能是,使用一个 auto_ptr 对象的 get 函数的结果来初始化或者 reset另一个 auto_ptr 对象。

3)不要使用 auto_ptr 对象保存指向动态分配数组的指针。当auto_ptr 对象被删除的时候,它只释放一个对象—它使用普通delete 操作符,而不用数组的 delete [] 操作符。

4)不要将 auto_ptr 对象存储在容器中。容器要求所保存的类型定义复制和赋值操作符,使它们表现得类似于内置类型的操作符:在复制(或者赋值)之后,两个对象必须具有相同值,auto_ptr 类不满足这个要求。

11、异常说明

1)定义

示例

void recoup(int) throw(runtime_error);
void no_problem() throw(); //空说明列表指出函数不抛出任何异常

异常说明是函数接口的一部分,函数定义以及该函数的任意声明必须具有相同的异常说明。如果函数声明没有指定异常说明,则该函数可以抛出任意类型的异常。

2)基类的虚函数的异常说明可以与派生类中对应虚函数的异常说明不同,但派生类虚函数的异常说明应当更严格。基类中虚函数异常列表是派生类异常列表的超集。

12、可以在函数指针的定义中提供异常说明。在用另一指针初始化带异常说明的函数的指针,或者将后者赋值给函数地址的时候,两个指针的异常说明不必相同,但是,源指针的异常说明必须至少与目标指针的一样严格

示例

void recoup(int) throw(runtime_error);
// ok: recoup is as restrictive as pf1
void (*pf1)(int) throw(runtime_error) = recoup;
// ok: recoup is more restrictive than pf2
void (*pf2)(int) throw(runtime_error, logic_error) = recoup;
// error: recoup is less restrictive than pf3
void (*pf3)(int) throw() = recoup;
// ok: recoup is more restrictive than pf4
void (*pf4)(int) = recoup;

参考

[1] http://www.cnblogs.com/mydomain/archive/2011/04/14/2016565.html