Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning const char*; how ugly is static?

Tags:

c++

python

c

swig

For reasons beyond my control, I need to return const char* from a function, but I don't know what the chars need to be at compile time. My solution is something like the following:

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

The static prevents the string's destruction on exiting the function, but it also means that the memory sticks around until my program exits (right?). Because the returned string can occasionally be huge (GBs), 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 this guaranteed to work? Is there a better way?

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

like image 787
Mike Avatar asked Dec 01 '22 23:12

Mike


2 Answers

static presents additional troubles besides the allocation scope:

  • The function is not reentrant
  • There is no way to clean up when the caller is done with the return value

Any reason not to return the value and let the caller 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
like image 162
wallyk Avatar answered Dec 04 '22 11:12

wallyk


As @Prætorian said, SWIG can return std::string to Python. Here's an example from the SWIG example I think you are looking at. Also shown is a way to avoid using a reserved name in C++:

x.i

%module x

%{
#include "x.h"
%}

%include <windows.i>
%include <std_string.i>
%rename(__str__) display;
%include "x.h"

x.h

#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
};

Output

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]
like image 43
Mark Tolonen Avatar answered Dec 04 '22 11:12

Mark Tolonen