[C ++ design skills] raiI Mechanism in C ++

Source: Internet
Author: User

Author: gnuhpc
Source: http://www.cnblogs.com/gnuhpc/

1. Concept

Resource Acquisition is initializationThe Mechanism was first proposed by Bjarne stroustrup. To solve this problem:

In C ++, if you need to release some resources at the end of the program segment, it is normal that there is no problem, but when an exception is thrown, the statement for releasing resources will not be executed. So Bjarne stroustrup thought that the destructor of the object placed in this program segment (stack frame) was the place where the resource release code could be run, because stack winding ensures that all their destructor are executed. Benefits of moving initialization and resource release to a packaging class:

  • Ensures normal resource release
  • Eliminating the lengthy and repetitive cleaning logic that is not necessarily executed in exception handling, thus ensuring code exception security.
  • Simplified code size.

2. Application scenarios

1) File Operations

We can use this mechanism to package file operations to complete an exceptionally secure file class. In implementation, note that the replication constructor and value assignment are privatized. This is done through a private inheritance class, because these two operations do not make sense here. Of course, this is not what raiI requires.

/* * ===================================================================================== * *       Filename:  file.cpp * *    Description:  RAII for files * *        Version:  1.0 *        Created:  05/09/2011 06:57:43 PM *       Revision:  none *       Compiler:  g++ * *         Author:  gnuhpc, warmbupt@gmail.com * * ===================================================================================== */#include <IOSTREAM>#include <STDEXCEPT>#include <CSTDIO>using namespace std;class NonCopyable{public:NonCopyable(){};private:    NonCopyable (NonCopyable const &); // private copy constructor    NonCopyable & operator = (NonCopyable const &); // private assignment operator};class SafeFile:NonCopyable{public:    SafeFile(const char* filename):fileHandler(fopen(filename,"w+"))    {        if( fileHandler == NULL )        {            throw runtime_error("Open Error!");        }    }    ~SafeFile()    {        fclose(fileHandler);    }    void write(const char* str)    {        if( fputs(str,fileHandler)==EOF )        {            throw runtime_error("Write Error!");        }    }    void write(const char* buffer, size_t num)    {        if( num!=0 && fwrite(buffer,num,1,fileHandler)==0 )        {            throw runtime_error("Write Error!");        }    }private:    FILE *fileHandler;    SafeFile(const SafeFile&);    SafeFile &operator =(const SafeFile&);};int main(int argc, char *argv[]){    SafeFile testVar("foo.test");    testVar.write("Hello RAII");}

The structure of C ++ determines its native support for raiI. in Java, it is unknown when objects are destroyed, so it can be used in Java.Try-finallyPerform related processing.

2) intelligent pointer Simulation

A more complex example is to simulate smart pointers. The abstracted raiI class implements an operator * and directly returns the stored pointer:

Now we have a class:

class Example {  SomeResource* p_;  SomeResource* p2_;public:  Example() :    p_(new SomeResource()),    p2_(new SomeResource()) {    std::cout << "Creating Example, allocating SomeResource!/n";  }  Example(const Example& other) :    p_(new SomeResource(*other.p_)),    p2_(new SomeResource(*other.p2_)) {}  Example& operator=(const Example& other) {    // Self assignment?    if (this==&other)      return *this;    *p_=*other.p_;    *p2_=*other.p2_;    return *this;  }  ~Example() {     std::cout << "Deleting Example, freeing SomeResource!/n";     delete p_;     delete p2_;  }};

Assume thatSomeResourceIf the resource to which P _ points is created but P2 _ points to fails to be created, the entire instance of example fails to be created, the resource to which P _ points has memory leakage.

The following method can be used as an alternative:

Example() : p_(0),p2_(0){  try {    p_=new SomeResource();    p2_=new SomeResource("H",true);    std::cout << "Creating Example, allocating SomeResource!/n";  }  catch(...) {    delete p2_;    delete p_;    throw;  }}

However, we can use an object to call the features of the Destructor when it leaves a domain, complete initialization in the constructor, and complete cleaning in the destructor, put the pointer to be operated and protected into raiI as a member variable.

template <TYPENAME T>class RAII {  T* p_;public:  explicit RAII(T* p) : p_(p) {}  ~RAII() {    delete p_;  }  void reset(T* p) {    delete p_;    p_=p;  }  T* get() const {     return p_;  }  T& operator*() const {     return *p_;  }  void swap(RAII& other) {    std::swap(p_,other.p_);  }private:  RAII(const RAII& other);  RAII& operator=(const RAII& other);};

In specific use, we put the protected pointer someresource in raiI:

class Example {  RAII<SOMERESOURCE> p_;  RAII<SOMERESOURCE> p2_;public:  Example() :    p_(new SomeResource()),    p2_(new SomeResource()) {}  Example(const Example& other)    : p_(new SomeResource(*other.p_)),      p2_(new SomeResource(*other.p2_)) {}  Example& operator=(const Example& other) {    // Self assignment?    if (this==&other)      return *this;    *p_=*other.p_;    *p2_=*other.p2_;    return *this;  }  ~Example() {    std::cout << "Deleting Example, freeing SomeResource!/n";  }};

Now, even if P _ succeeds but P2 _ fails, the raiI destructor will be called in stack winding to ensure that the someresource pointed to by P _ is destructed. This method is different from the interface corresponding to the pointer type that needs to be combined in Example 1. The interface is not encapsulated here. Of course, in Example 1, you can also provide a getpointer function to directly provide the handle.

In fact, in example, there is no need for destructor, because the raiI class will take care of all this. This is a bit likeauto_ptrThis article does not intend to discuss the topic of smart pointers in depth.

3) Lock Operation

/* * ===================================================================================== * *       Filename:  threadlock.cpp * *    Description:  Lock for RAII * *        Version:  1.0 *        Created:  05/09/2011 10:16:13 PM *       Revision:  none *       Compiler:  g++ * *         Author:  gnuhpc (http://blog.csdn.net/gnuhpc), warmbupt@gmail.com * * ===================================================================================== */#include <CSTDIO>#include <STDLIB.H>#include <PTHREAD.H>int counter = 0;void* routine(void *ptr);pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;class NonCopyable{public:    NonCopyable(){};private:    NonCopyable (NonCopyable const &); // private copy constructor    NonCopyable & operator = (NonCopyable const &); // private assignment operator};class ScopeMutex:NonCopyable{public:    ScopeMutex(pthread_mutex_t* mutex):mutex_(mutex){        pthread_mutex_lock( mutex_ );    }    ~ScopeMutex(){        pthread_mutex_unlock( mutex_ );    }private:    pthread_mutex_t *mutex_;};int main(int argc, char *argv[]){    int rc1, rc2;    pthread_t thread1, thread2;    if( (rc1=pthread_create( &thread1, NULL, routine, NULL)) )    {        printf("Thread creation failed: %d/n", rc1);    }    if( (rc2=pthread_create( &thread2, NULL, routine, NULL)) )    {        printf("Thread creation failed: %d/n", rc1);    }    pthread_join( thread1, NULL);    pthread_join( thread2, NULL);}void* routine(void *ptr){    ScopeMutex scopeMutex(&mutex);    counter++;    printf("%d/n",counter);}

3. Summary

The raiI mechanism ensures exceptional security and provides security for programmers when writing programs with dynamically allocated memory. The disadvantage is that some operations may throw an exception. If the error cannot be passed out in the destructor, The Destructor must handle the exception on its own. This is complicated in some cases.

4. References

Http://www.codeproject.com/KB/cpp/RAIIFactory.aspx this article completed a raiI factory in a factory approach.

Http://www.informit.com/articles/printerfriendly.aspx? P = 21084 discusses some abnormal security situations. The security of the assignment operator is worth noting.

 

Author: gnuhpc
Source: http://www.cnblogs.com/gnuhpc/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.