Whenever you deal with a resource that needs paired acquire/release
function call, encapsulate that resource in an object. Such as:
fopen/fclose, lock/unlock, and new/delete.
When implementing RAII, be conscious of copy construction and
assignment. the compiler-generated version probably won’t be correct.
If it’s not copyable, use =delete , if it’s copyable, duplicate the resource.
You also can use smart_pointer in this scenario too.
The basic idea of RAII is to represent a resource by a local object, so that
the local objectâĂŹs destructor will release the resource. That is
to say: To prevent resource leaks, use RAII objects that acquire
resources in their constructors and release them in their destructors.
Another good example RAII is unique_ptr. The idea of smart pointer is
putting *p into a local pointer-like object, then when it go out scope or
unwind-stack when exception is thrown, It will call destructor, then delete
p.
We should consider resource generically, pointer *p pointed to a new
object is resource, A handle to a file is a resource to. We wraphandle to a file into ifstream, and wrap pointer *p intosmart_pointer
Just like return value, Exception will skip all the statement below the throw,
In C++, It doesn’t support finally statement sometimes. At this time, we
need to use RAII.
For this problem, you should use smart pointer to declare a auto object. If
you use string object, It’s ok. So in previous example, you can use
smart pointer, it will help you to avoid memory leakage problem.
In you ctor, If you use new and new failed and throw a exception, the
destructor will not be called. You can use auto_ptr as member data
and use init list to initialzie it. see more effective C++ exception
chapter.
Don’t use C FILE* and char [] as string. Use iofile class and string object,
because they are exception safe
Any time when you use new, consider if there are c++ container
or object.
If not, use smart_pointer.
Another example is when you make program based on Win API.
Use pointer and handle; In this way, You have to use pointer, Maybe
you need some customized action in runtime , Use handle is onlymethod to use this resource or any other reason. And this time,
you have to write your own dtor.
For auto member resource: 1)Same life duration(RAII),2)exclusive ownship to a single obj, but it’s copyable(Aa1 = a2). 3)move with efficiency(A a1 = A() ) . If auto
member has it’s own copy and move special function, You don’t
need to write any special function in your class. You follow the
"Rule of Zero".
For raw pointer and handle: 1) default copy ctor will cause twopointer or handle refer the same resource, It’s absolutelyBAD SMELL of code 2) So you have to follow "Rule of five"to build your special member function. 3) After you build fivespecial member function, you get RAII and exclusiveownship to a single object, and copyable and efficient move
For uniqu_ptr; 1) Same life(RAII) 2)exclusive ownship but notcopyable 3) uniqu_ptr support move operation. You still follow
"rule of zero"
Even with uniqu_ptr member, If you follow "rule of zero",
that is to say that you don’t provide any customized special
member function, then the class is not copyable. But if you
build copy ctor by youself, get raw pointer from origin side,
and build a new uniqu_ptr member from origin side’s raw
pointer, you can implement copyable, and code smell better
than raw pointer with "Rule of Five". So in this way, It’s notrecommended to use raw pointer in RAII and ownershipcontext.
For shared_ptr; 1) Not a RAII 2) shared ownship, 3) copyableand moveable. When you move a shared_ptr, origin one is set to
nullptr and ref count doesn’t increas. You still follow "rule of
zero".
Conclusion, If you consider RAII and ownship at the same time,thing will become complex so I would like to give you some examples to
illustrate them.
Prefer to use auto member for most of time! It follow "Rule of
Five" and support copyable and movable.
For special demand, for example Car class, people can custom its
engine, and buy two at the same time. In this context, you car class
should use raw pointer, 1) auto member doesn’t support custom 2)
uniqu_ptr doesn’t support copyable. And you have to follow "Rule of
Five"
For special context, It doesn’t support object copy: for example 1)
Person class in semantic; 2) other perform consideration, Class Bigint
[30000];; 3) Other implementation constrain, such as iostream class.
Under such context, you can use uniqu_ptr to manage the resource
and implement uncopyable.
classPerson{ uniqu_ptr<Resource>pRes; }
For special context, shared resource, you can use shared_ptr. You still
can follow "Rule of zero" and resource will be deleted when ref count is
0.
classStudent{ shared_ptr<SchoolBus>pBus }
To know semantic of two smart pointers. Don’t use them just replace
raw pointer.