Return const char *; how ugly is static?

For reasons beyond my control, I need to return const char* from the function, but I don't know what char needed at compile time. My solution looks something like this:

 const char* __str__() { static std::string String; String = [some fancy stuff]; return String.c_str(); } 

static prevents line breaks when exiting a function, but it also means that the memory is erased until my program exits (right?). Since the returned string can sometimes be huge (GB), this can be a real problem.

I usually avoid pointers at all costs and only ever use static for class members, so I'm not 100% sure what I'm doing. Is it guaranteed? Is there a better way?

[The context of this question is to print a complex object in python using the __str__ method. I define a method in my C ++ code, which is then wrapped with SWIG. The SWIG example shows the use of static , but it is not clear to me that this is the only way. I am open to suggestions.]

+4
source share
3 answers

As Prætorian said, SWIG can return std :: string in Python. Here is an example from the SWIG example that I think you're looking at. It also shows how to avoid using a reserved name in C ++:

xi

 %module x %{ #include "xh" %} %include <windows.i> %include <std_string.i> %rename(__str__) display; %include "xh" 

xh

 #include <sstream> #include <string> class Vector { public: double x,y,z; Vector(double a,double b,double c):x(a),y(b),z(c) {} ~Vector() {} #ifdef SWIG %extend { std::string display() { std::ostringstream temp; temp << '[' << $self->x << ',' << $self->y << ',' << $self->z << ']'; return temp.str(); } } #endif }; 

Exit

 Python 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import x >>> v = x.Vector(1.0,2.5,3.0) >>> print v [1,2.5,3] 
+5
source

static presents additional problems besides the selection area:

  • The function is not reentrant
  • Cannot perform a cleanup when the caller has a return value

Any reason not to return the value and allow the caller to free it:

 const char* __str__() { char *s = malloc(2 * 1024 * 1024 * 1024); // 2 GB [some fancy stuff with s]; return s; } ... const char *magic = __str__(); [do something with magic] free (magic); magic = NULL; // all done 
+10
source

This is guaranteed to work with significant reservations.

All reservations come down to two main issues, which are combined in such a way that it is not very pleasant:

  • In your complete program, there is only one instance of String .
  • String not a constant.

This will cause you all sorts of interesting problems. For example, if you call __str__ again to another place in your program, anyone who saved a copy of the const char * that you passed back may end up with an invalid pointer. And even if it is not, they will return a pointer to the memory that has changed. In short, the result will be undefined behavior.

Another example: if you call __str__ from more than one thread, it will explode at some point, since both threads are trying to change String at the same time.

Fortunately, you do not have a static initialization task. String guaranteed to be initialized the first time __str__ called.

You can solve the String problem by staying forever by calling String.clear() in __str__ if you are sure that no one has a const char * indicating the status of your String . String.clear() free up any storage that it can use.

Personally, I would use this only as a last resort. The possibility of random parts of the program throwing a pointer could endlessly bother me. There is no clear indicator of the lifetime of this pointer, except that it cannot be guaranteed that it will work if __str__ ever called again. But then again, it may be, depending on what exactly __str__ does.

In addition, __str__ is a bad name to use. Names containing two consecutive underscores are reserved for implementation in C ++.

+3
source

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


All Articles