Effective C++ 条款15学习笔记:在资源管理类型中提供对原始资源的访问
2011-09-22 23:15
531 查看
Provide access to raw resources in resource-managing classes
1.如何访问原始资源
在上两条款我们知道如何使用智能指针管理我们的申请的资源,但是读者是否发现,我们如何去访问我们原始资源的方法呢?在这一条款将得到解答以及类型转换的相关问题。
首先,我们用代码来说话吧,及输出的结构看到
图一
从这里我们可以看到,程序输出了我们想要的结果。如书中所述:
tr1::shared_ptr 和 auto_ptr 都提供了一个 get 成员函数来进行显式转换,也就是说,返回一个智能指针对象中的裸指针(的副本):
myClass* myC=apMy.get();//////
似乎所有的智能指针类,包括 tr1::shared_ptr 和 auto_ptr 等等,都会重载指针解析运算符( operator-> 和 operator* ),这便使得对原始裸指针进行隐式转换成为现实,在这里我就不实际举例子了。下面使用书中的片段代码来说明一下问题吧:
出色的资源管理类型可以避免资源泄露并有效的管理资源,但世界并非是如你所愿的。当某个API需要使用资源管理类型把持的原始资源时,这样的麻烦又会随之而来。
也许您注意到了
就出现了问题。结果大家可以试一下。
2.隐式转换
因为有时候要取得RAII对象内原始资源,
RAII设计者使用了一种隐式转换函数,
如果让资源管理类型提供隐式转换函数,可以让行为变的更自然,但这样的作法没有好下场,只会增加客户端发生错误的机率。比如下面的代码(简单的编写了一个自定义的AutoPtr,它重载了隐式转换operator):
pTP也获得了apI提供的Point指针,当apI作用域结束后或显示调用了Release方法,pTP也就成了迷途指针了。通常来说提供Get方法是比较大众切容易接受的正确方法,它将隐式转换所带来的恶意最小化。
也许在诸如auto_ptr、shared_ptr只提供原始指针的访问违背了面向对象的封装性,可能是令人产生误解和迷惑的地方。因为RAII classes并不是为了封装某物而存在的,更多的它只是一种模版编程的概念。
pTP也获得了apI提供的Point指针,当apI作用域结束后或显示调用了Release方法,pTP也就成了迷途指针了。通常来说提供Get方法是比较大众切容易接受的正确方法,它将隐式转换所带来的恶意最小化。
也许在诸如auto_ptr、shared_ptr只提供原始指针的访问违背了面向对象的封装性,可能是令人产生误解和迷惑的地方。因为RAII classes并不是为了封装某物而存在的,更多的它只是一种模版编程的概念。
牢记在心
l API 通常需要访问原始资源,因此每个 RAII 类都应该提供一个途径来获取它所管理的资源。
l 访问可以通过显式转换或隐式转换来实现。一般情况下,显式转换更安全,但是隐式转换对于客户端程序员来说使用更方便。
1.如何访问原始资源
在上两条款我们知道如何使用智能指针管理我们的申请的资源,但是读者是否发现,我们如何去访问我们原始资源的方法呢?在这一条款将得到解答以及类型转换的相关问题。
首先,我们用代码来说话吧,及输出的结构看到
// pro_acce.cpp : 定义控制台应用程序的入口点。 //2011/9/21 by wallwind on sunrise; #include "stdafx.h" #include <iostream> #include <memory> using namespace std; class myClass { public : myClass() { cout<<"myClass()"<<endl; } ~myClass() { cout<<"~myClass()"<<endl; } void printFunc() { cout<<"printFunc()"<<endl; } int getType()const { return type; } private: int type; }; myClass* creatMyClass() { myClass *my=new myClass(); return my; } void issue(myClass *my) { delete my; } int _tmain(int argc, _TCHAR* argv[]) { auto_ptr<myClass> apMy(creatMyClass()); myClass* myC=apMy.get();//////auto_ptr 给我们提供的函数,用来访问原始资源 myC->printFunc();//////调用了myClass的方法 return 0; }
图一
从这里我们可以看到,程序输出了我们想要的结果。如书中所述:
tr1::shared_ptr 和 auto_ptr 都提供了一个 get 成员函数来进行显式转换,也就是说,返回一个智能指针对象中的裸指针(的副本):
myClass* myC=apMy.get();//////
似乎所有的智能指针类,包括 tr1::shared_ptr 和 auto_ptr 等等,都会重载指针解析运算符( operator-> 和 operator* ),这便使得对原始裸指针进行隐式转换成为现实,在这里我就不实际举例子了。下面使用书中的片段代码来说明一下问题吧:
std::tr1::shared_ptr<Investment> pi1(createInvestment()); // 使用 tr1::shared_ptr // 管理资源 bool taxable1 = !(pi1->isTaxFree()); // 通过 operator-> 访问资源 ... std::auto_ptr<Investment> pi2(createInvestment()); // 使用 auto_ptr 管理资源 bool taxable2 = !((*pi2).isTaxFree()); // 通过 operator* 访问资源
出色的资源管理类型可以避免资源泄露并有效的管理资源,但世界并非是如你所愿的。当某个API需要使用资源管理类型把持的原始资源时,这样的麻烦又会随之而来。
也许您注意到了
void issue(myClass *my) { delete my; } 这个函数没有使用到,那么当你使用这个时候 int _tmain(int argc, _TCHAR* argv[]) { auto_ptr<myClass> apMy(creatMyClass()); issue(apMy.get()); return 0; }
就出现了问题。结果大家可以试一下。
2.隐式转换
因为有时候要取得RAII对象内原始资源,
RAII设计者使用了一种隐式转换函数,
如果让资源管理类型提供隐式转换函数,可以让行为变的更自然,但这样的作法没有好下场,只会增加客户端发生错误的机率。比如下面的代码(简单的编写了一个自定义的AutoPtr,它重载了隐式转换operator):
#include "stdafx.h" #include <stdlib.h> #include <memory> #include <string> using namespace std; template<typename T> class AutoPtr { public: AutoPtr(T *tP) : _tP(tP), _released(false) { } ~AutoPtr() { Release(); } T* operator->() { return _tP; } operator T*() const { return _tP; } void Release(void) { if (!_released) { delete _tP; _released = true; } } private: T *_tP; bool _released; }; typedef struct Point { double X; double Y; }; void PrintPoint(Point *pTP) { } int _tmain(int argc, _TCHAR* argv[]) { AutoPtr<Point> apI(new Point()); PrintPoint(apI); Point *pTP = apI; apI.Release(); system("pause"); return 0; }
pTP也获得了apI提供的Point指针,当apI作用域结束后或显示调用了Release方法,pTP也就成了迷途指针了。通常来说提供Get方法是比较大众切容易接受的正确方法,它将隐式转换所带来的恶意最小化。
也许在诸如auto_ptr、shared_ptr只提供原始指针的访问违背了面向对象的封装性,可能是令人产生误解和迷惑的地方。因为RAII classes并不是为了封装某物而存在的,更多的它只是一种模版编程的概念。
#include "stdafx.h" #include <stdlib.h> #include <memory> #include <string> using namespace std; template<typename T> class AutoPtr { public: AutoPtr(T *tP) : _tP(tP), _released(false) { } ~AutoPtr() { Release(); } T* operator->() { return _tP; } operator T*() const { return _tP; } void Release(void) { if (!_released) { delete _tP; _released = true; } } private: T *_tP; bool _released; }; typedef struct Point { double X; double Y; }; void PrintPoint(Point *pTP) { } int _tmain(int argc, _TCHAR* argv[]) { AutoPtr<Point> apI(new Point()); PrintPoint(apI); Point *pTP = apI; apI.Release(); system("pause"); return 0; }
pTP也获得了apI提供的Point指针,当apI作用域结束后或显示调用了Release方法,pTP也就成了迷途指针了。通常来说提供Get方法是比较大众切容易接受的正确方法,它将隐式转换所带来的恶意最小化。
也许在诸如auto_ptr、shared_ptr只提供原始指针的访问违背了面向对象的封装性,可能是令人产生误解和迷惑的地方。因为RAII classes并不是为了封装某物而存在的,更多的它只是一种模版编程的概念。
牢记在心
l API 通常需要访问原始资源,因此每个 RAII 类都应该提供一个途径来获取它所管理的资源。
l 访问可以通过显式转换或隐式转换来实现。一般情况下,显式转换更安全,但是隐式转换对于客户端程序员来说使用更方便。
相关文章推荐
- 《Effect C++》学习------条款15:在资源管理中提供对原始资源的访问
- Effective C++ 条款15 在资源管理类中提供对资源的原始访问
- 读书笔记《Effective C++》条款15:在资源管理类中提供对原始资源的访问
- effective C++ 条款 15:在资源管理类中提供对原始资源的访问
- 《Effective C++》学习笔记条款15 在资源管理类中提供对原始资源的访问
- Effective C++ 条款15、16 在资源管理类中提供对原始资源的访问||成对使用new 与 delete要采取相同形式
- Effective C++:条款15:在资源管理类提供对原始资源的访问
- Effective C++ 条款15:在资源管理类中提供对原始资源的访问
- effective c++ 条款15 在资源管理类中提供对原始资源的访问
- 【Effective c++】条款15:在资源管理类中提供对原始资源的访问
- 读书笔记《Effective c++》 条款15 在资源管理类中提供对原始资源的访问
- Effective C++(15) 在资源管理类中提供对原始资源的访问
- 条款15:在资源管理类中提供对原始资源的访问
- 条款15:在资源管理类中提供对原始资源的访问
- 条款15:在资源管理类中提供对原始资源的访问
- 条款15:在资源管理类张提供对原始资源的访问
- Effective C++ 学记之15 在资源管理类中提供对原始资源的访问
- 条款15:在资源管理类中提供对原始资源的访问
- 条款15、在资源管理类中提供对原始资源的访问
- 条款15 在资源管理类中提供对原始资源的访问