返回const char *;静态是多么丑陋?

时间:2012-03-21 22:54:21

标签: c++ python c swig

由于我无法控制的原因,我需要从函数返回const char*,但我不知道char在编译时需要什么。我的解决方案如下:

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

static可以防止字符串在退出函数时被破坏,但这也意味着内存会一直存在,直到我的程序退出(对吗?)。因为返回的字符串有时可能巨大(GB),这可能是一个真正的问题。

我通常会不惜一切代价避免使用指针,并且只对类成员使用static,所以我不能100%确定我在做什么。这保证有效吗?还有更好的方法吗?

[这个问题的上下文是使用__str__方法在python中打印一个复杂的对象。我在我的c ++代码中定义了该方法,然后由SWIG包装。 SWIG示例显示了static的使用,但我不清楚这是唯一的方法。我愿意接受建议。]

3 个答案:

答案 0 :(得分:10)

static除分配范围外还会出现其他问题:

  • 该功能不可重入
  • 调用者使用返回值
  • 时无法清除

任何理由不返回该值并让调用者释放它?:

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

答案 1 :(得分:5)

正如@Prætorian所说,SWIG可以将std :: string返回给Python。以下是我认为您正在研究的S​​WIG示例中的示例。还显示了一种避免在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
};

输出

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]

答案 2 :(得分:3)

这保证可行,但有重要的警告。

所有警告归结为两个基本问题,这些问题以一种不太令人愉快的方式结合在一起:

  1. 整个计划中只有String的一个实例。
  2. String不是常数。
  3. 这会引起各种有趣的问题。例如,如果您在程序中的其他位置再次调用__str__,则任何保存了您传回给它们的const char *副本的人可能最终都会持有无效指针。即使它们不是,它们最终也会指向已经改变的记忆。简而言之,结果将是未定义的行为。

    另一个例子,如果你从多个线程调用__str__,它会在某个时刻爆炸,因为两个线程都试图同时修改String

    幸运的是,您没有静态初始化顺序问题。保证String在您第一次拨打__str__时初始化。

    如果您确定没有任何人String指向该州,则可以通过String.clear()中的__str__来解决const char *永远留在身边的问题您的StringString.clear()将释放它可能正在使用的任何存储空间。

    就个人而言,我只会将此作为最后的手段。程序的随机部分有可能使指针松散,这会让我无休止地担心。没有明确指示此指针的生命周期,除了在再次调用__str__时无法保证工作的事实。但话又说回来,这可能取决于__str__究竟是什么。

    此外,__str__是一个糟糕的名称。包含两个连续下划线的名称保留用于C ++实现。