Using RAII with a pointer to a character

I see many RAII example classes wrapping files.

I tried to adapt these examples without luck to the character pointer.

The library I use has functions that take the address of a character pointer (declared as get_me_a_string (char ** x)). These functions allocate memory for this character pointer and leave it to the end user of the library to clear it in their own code.

So I have a code that looks like this ...

char* a = NULL; char* b = NULL; char* c = NULL; get_me_a_string(&a); if(a == NULL){ return; } get_me_a_beer(&b); if(b == NULL){ if(a != NULL){ free(a); } return; } get_me_something(&c); if(c == NULL){ if(a != NULL){ free(a); } if(b != NULL){ free(b); } return; } if(a != NULL){ free(a); } if(b != NULL){ free(b); } if(a != NULL){ free(b); } 

RAII seems to be the answer to this mess, which I have above. Can someone provide a simple C ++ class that wraps char * rather than FILE *?

thanks

+4
source share
8 answers

Something is already available in the standard library: it is called std::string .

Edit: In the light of new information:

He will allocate memory and fill it up. I could copy the contents into a new std :: string object, but I still have to free the memory that was allocated by the function.

This is a poor design in terms of implementation - the module that allocates should be responsible for the release.

Ok, now that I got this from my system: you can use boost::shared_ptr to free.

 template<typename T> struct free_functor { void operator() (T* ptr) { free(ptr); ptr=NULL; } }; shared_ptr<X> px(&x, free_functor()); 
+5
source

Very simple implementation (what you should do noncopyable, etc.).

 struct CharWrapper { char* str; CharWrapper(): str() {} // Initialize NULL ~CharWrapper() { free(str); } // Conversions to be usable with C functions operator char**() { return &str; } operator char*() { return str; } }; 

This is technically not RAII, since proper initialization occurs later than the constructor, but it will take care of cleaning.

+2
source

You can try something like this:

 template <typename T> class AutoDeleteArray { public: explicit AutoDeleteArray(const T* ptr) : ptr_(ptr) {} ~AutoDeleteArray() { delete [] ptr_; // if needed use free instead // free(ptr_); } private: T *ptr_; }; // and then you can use it like: { char* a = NULL; get_me_a_string(&a); if(a == NULL) return; AutoDeleteArray<char> auto_delete_a(a); } 

This is not the most reliable solution, but may be enough for this purpose.

PS: I wonder if std::tr1::shared_ptr work with a regular deleter?

+1
source

I think auto_ptr is what you want

or boost shared_ptr if auto_ptr semantics don't work for you

0
source

Either use plain std::string , or boost :: scoped_array for local arrays, or boost :: shared_array for shared strings (the latter allows you to provide a custom remote call to call free() .)

0
source

Thank you all for your answers.

Unfortunately, I cannot use boost or other libraries in this project ... so all these suggestions are useless to me.

I looked at things like exception handling in C, like here ... http://www.halfbakery.com/idea/C_20exception_20handling_20macros

And then I looked at why C ++ doesn't finally have a Java look and stumbled upon this RAII stuff.

I'm still not sure if I will follow the path of the destructor and only make C ++ code or stick to the C exception macro (which uses the awful goto :)

Tronic suggested something like the following. With RAII, or destructors in general, should they be proof of segfault? I guess not.

The only thing I don't like is the fact that now I have to use listing (char *) in my printf statements.

 #include <stdio.h> #include <stdlib.h> #include <string.h> struct CharWrapper { char* str; CharWrapper(): str() {} // Initialize NULL ~CharWrapper() { printf("%d auto-freed\n", str); free(str); } // Conversions to be usable with C functions operator char*() { return str; } operator char**() { return &str; } }; // a crappy library function that relies // on the caller to free the memory int get_a_str(char **x){ *x = (char*)malloc(80 * sizeof(char)); strcpy(*x, "Hello there!"); printf("%d allocated\n", *x); return 0; } int main(int argc, char *argv[]){ CharWrapper cw; get_a_str(cw); if(argc > 1 && strcmp(argv[1], "segfault") == 0){ // lets segfault int *bad_ptr = NULL; bad_ptr[8675309] = 8675309; } printf("the string is : '%s'\n", (char*)cw); return 0; } 
0
source

An alternative solution would be something like this, here's how I write this code in C:

 char* a = NULL; char* b = NULL; char* c = NULL; get_me_a_string(&a); if (!a) { goto cleanup; } get_me_a_beer(&b); if (!b) { goto cleanup; } get_me_something(&c); if (!c) { goto cleanup; } /* ... */ cleanup: /* free-ing a NULL pointer will not cause any issues * ( see C89-4.10.3.2 or C99-7.20.3.2) * but you can include those checks here as well * if you are so inclined */ free(a); free(b); free(c); 
0
source

Since you say you cannot use boost, writing a not-so-simple smart pointer that does not transfer or transfer resources is not very difficult.

There is something basic here. You can specify a delete functor as a template parameter. I don’t particularly like operator conversions, so use the get () method.

Add other methods such as release () and reset () as desired.

 #include <cstdio> #include <cstring> #include <cstdlib> struct Free_er { void operator()(char* p) const { free(p); } }; template <class T, class Deleter> class UniquePointer { T* ptr; UniquePointer(const UniquePointer&); UniquePointer& operator=(const UniquePointer&); public: explicit UniquePointer(T* p = 0): ptr(p) {} ~UniquePointer() { Deleter()(ptr); } T* get() const { return ptr; } T** address() { return &ptr; } //it is risky to give out this, but oh well... }; void stupid_fun(char** s) { *s = static_cast<char*>(std::malloc(100)); } int main() { UniquePointer<char, Free_er> my_string; stupid_fun(my_string.address()); std::strcpy(my_string.get(), "Hello world"); std::puts(my_string.get()); } 
0
source

Source: https://habr.com/ru/post/1300097/


All Articles