c++ dll接口返回字符串

来源:互联网 发布:js.anji ceva.com 编辑:程序博客网 时间:2024/05/17 04:04

假如说,我们封装的dll 有返回字符串的需求,比如有这么个函数

string oneclass::getString()

{

string res =  string();

...do something,,,

return res;

}

的话,如果我们直接使用std::string 作为接口返回值的话,是会有一些问题的 具体的问题 可以百度 "尽量不要在Dll的接口中使用string作为参数" 可以了解到,这里主要列举两个可能会导致的问题.

1.由于编译器版本或者工程设置不一致,可能会出现跨模块内存分配和释放的问题,进而出现崩溃的现象,

2.配置不一致,会出现乱码的情况.


那我们确实有传递字符串的需求,那该怎么办呢?

查阅网上,汇总的资料,有以下总结:

首先肯定是要,哪个模块new出来的东西,那就要哪个模块去释放,不能跨模块释放,否则就会出问题

比如 

char* oneclass::getString()

{

char* res =  new char[100];

...do something,,,

return res;

}

然后 调用dll的地方 就算记得 delete了也不行

总结了一下,网上的方法有以下几个:

1.返回全局变量的地址或者静态变量的地址

也就是说在dll里面搞一个全局变量,然后每次返回的时候,把返回结果赋值到全局变量里面,再将全局变量的地址返回就可以了.

但是这样子做的话,好处是不用马上去释放了,坏处就是,一直占用着内存,而且一个函数就用一个全局变量的话,函数多了就全局变量的数目就上去了,这个跟我们尽量减少全局变量或者静态变量的初衷是不一致的.此外,这个办法最严重的问题就是,无法多线程了,所以个人不推荐这个办法.

2.由调用者创建,销毁字符串

也就是 改变接口,改为这样

void oneclass::getString( char* res)

{

...do something,,,

}

然后用的时候

char str[100];

getString(str);

这样子做,难就难在确定那个字符串长度上,你无法知道getString到底需要多长的字符串,定义太长浪费,太短又担心不够用,也是纠结.

3.dll 提供free方法 ,用于析构这些指针

也就是说,在dll里面new了指针,然后将其返回了,在调用的地方 用完以后,再调用dll的free方法,将指针传入,然后将其删除.这个方法倒是挺好的,这样new和delete都在dll模块了


不过我是采用了自己封装String类的方式来达到我的目的的

我封装了个string类 并将其导出.

头文件如下:

class CLASS_EXPORT String
{
public:
String(const char* c, bool copy = true);
String();
~String();
String(const String &other);
String& operator=(const String &rhs);
char* p();
char* create(const char* c, bool copy = true);
const char *__str__();
private:
char* _p;
bool _delete;
int _len;
};

 cpp内容如下:

String::String()
{
_p = NULL;
_len = 0;
_delete = false;
}


String::String(const String &other)
{
if (!other._p)
{
_p = NULL;
_len = 0;
_delete = false;
return;
}
this->_len = other._len;
_p = new char[other._len];
if (!other._delete)
{
memcpy(_p, other._p, _len - 1);
_p[_len - 1] = '\0';
}
else
{
memcpy(_p, other._p, _len);
}
_delete = true;
}


String::String(const char* c, bool copy /*= true*/)
{
int len = strlen(c);
if (copy)
{
len = strlen(c);
_p = new char[len + 1];
memcpy(_p, c, len);
_p[len] = '\0';
_delete = true;
}
else
{
_p = (char*)c;
}
this->_len = len + 1;
}


String::~String()
{
if (_p&&_delete)
{
delete[]_p;
_p = NULL;
}
}

char* String::p()
{
return _p;
}

char* String::create(const char* c, bool copy)
{
int len = strlen(c);
if (_p&&_delete)
{
delete[] _p;
_p = NULL;
}
if (copy)
{
_p = new char[len + 1];
memcpy(_p, c, len);
_p[len] = '\0';
_delete = true;
}
else
{
_p = (char*)c;
}
this->_len = len + 1;
return _p;
}

String& String::operator=(const String &rhs)
{
if (_p&&_delete)
{
delete _p;
}
if (!rhs._p)
{
_p = NULL;
_len = 0;
_delete = false;
return *this;
}
this->_len = rhs._len;
_p = new char[rhs._len];
if (!rhs._delete)
{
memcpy(_p, rhs._p, _len - 1);
_p[_len - 1] = '\0';
}
else
{
memcpy(_p, rhs._p, _len);
}
_delete = true;
return *this;
}

const char * String::__str__()
{
return _p;
}


这个只是个初级版本,里面问题也可能比较多,但是实测是可以解决问题的,用起来也比较方便,后面再慢慢完善.


0 0
原创粉丝点击