跳转到内容

C++ 编程/运算符/指针/智能指针

来自维基教科书,开放的书籍,面向开放的世界

智能指针

[编辑 | 编辑源代码]

使用原始指针存储分配的数据,然后在析构函数中清理它们,通常被认为是一个非常糟糕的想法,因为它容易出错。 即使将分配的数据暂时存储在原始指针中,然后在完成操作后删除它,也应该出于这个原因避免这样做。 例如,如果您的代码抛出异常,正确捕获异常并删除所有分配的对象可能很麻烦。

智能指针可以通过使用编译器和语言语义来确保指针内容在指针本身超出范围时自动释放,从而缓解这种头痛。

#include <memory>
class A
{
public:
        virtual ~A() {}
	virtual char val() = 0;
};

class B : public A
{
public:
	virtual char val() { return 'B'; }
};

A* get_a_new_b()
{
	return new B();
}

bool some_func()
{
	bool rval = true;
	std::auto_ptr<A> a( get_a_new_b() );
	try {
		std::cout << a->val();
	} catch(...) {
		if( !a.get() ) {
			throw "Memory allocation failure!";
		}
		rval = false;
	}
	return rval;
}


Clipboard

待办
可以注意到分配器使用的 rebind 模式是使用模板模板参数的替代方法。 从历史上看,STL 在 C++ 编译器提供对模板模板参数的支持之前就已基本开发完毕。 有趣的是,现代模板元编程风格提倡了一种类似于 rebind 的方法,而不是使用模板模板参数。


auto_ptr 具有严格所有权的语义,这意味着 auto_ptr 实例是负责对象生命周期的唯一实体。 如果复制一个 auto_ptr,源将丢失对该引用的引用。 例如

#include <iostream>
#include <memory>
using namespace std;
 
int main(int argc, char **arv)
{
    int *i = new int;
    auto_ptr<int> x(i);
    auto_ptr<int> y;
    
    y = x;
    
    cout << x.get() << endl;
    cout << y.get() << endl;
}

此代码将打印第一个 auto_ptr 对象的 NULL 地址,以及第二个的某个非 NULL 地址,这表明源对象在赋值期间(=)丢失了对该引用的引用。 示例中的原始指针 i 不应该被删除,因为它将由拥有该引用的 auto_ptr 删除。 事实上,new int 可以直接传递到 x 中,从而消除了对 i 的需要。

请注意,由 auto_ptr 指向的对象使用 operator delete 销毁;这意味着您应该只对使用 operator new 获得的指针使用 auto_ptr。 这不包括由 malloc()calloc()realloc()operator new[] 返回的指针。

华夏公益教科书