昨天做一个dll,代码很快写完了,然而使用得时候总是遇到string内部指针删除错误,郁闷了一天,今天没去公司,好好研究了一下。
首先看下下面这段代码,声明两个string对象:
std::
string
s1
=
"
wlwlxj
"
;
std:: string s2 = " lxjwlwww " ;
std:: string s2 = " lxjwlwww " ;
调试状态下可以看到内部指针:
s1=0x00364ff9
s2=0x00365061
然后执行
s2
=
s1;
按下f11,进入xstring源文件:
_Myt
&
operator
=
(
const
_Myt
&
_X) // 赋值操作符
{return (assign(_X)); } // 调用assign函数
{return (assign(_X)); } // 调用assign函数
继续进入assign(_X)函数:
_Myt
&
assign(
const
_Myt
&
_X)
{return (assign(_X, 0, npos)); } // 调用assign函数
继续进入assign函数,好戏都在这里面:
{return (assign(_X, 0, npos)); } // 调用assign函数
_Myt
&
assign(
const
_Myt
&
_X, size_type _P, size_type _M)
{if (_X.size() < _P)
_Xran();
size_type _N = _X.size() - _P;
if (_M < _N)
_N = _M;
if (this == &_X)
erase((size_type)(_P + _N)), erase(0, _P);
else if (0 < _N && _N == _X.size() // 这个分支意思就是如果拷贝源有内容且就是就是源本身,并且
&& _Refcnt(_X.c_str()) < _FROZEN - 1 // 源字符串引用次数少于255-1次(可见引用次数最多255次),
&& allocator == _X.allocator) //且源字符和目的字符分配器一致
{_Tidy(true); // 删除本身
_Ptr = (_E *)_X.c_str(); // 复制内容到目的串
_Len = _X.size();
_Res = _X.capacity();
++_Refcnt(_Ptr); } // 增加一次引用
else if (_Grow(_N, true))
{_Tr::copy(_Ptr, &_X.c_str()[_P], _N);
_Eos(_N); }
return (*this); }
{if (_X.size() < _P)
_Xran();
size_type _N = _X.size() - _P;
if (_M < _N)
_N = _M;
if (this == &_X)
erase((size_type)(_P + _N)), erase(0, _P);
else if (0 < _N && _N == _X.size() // 这个分支意思就是如果拷贝源有内容且就是就是源本身,并且
&& _Refcnt(_X.c_str()) < _FROZEN - 1 // 源字符串引用次数少于255-1次(可见引用次数最多255次),
&& allocator == _X.allocator) //且源字符和目的字符分配器一致
{_Tidy(true); // 删除本身
_Ptr = (_E *)_X.c_str(); // 复制内容到目的串
_Len = _X.size();
_Res = _X.capacity();
++_Refcnt(_Ptr); } // 增加一次引用
else if (_Grow(_N, true))
{_Tr::copy(_Ptr, &_X.c_str()[_P], _N);
_Eos(_N); }
return (*this); }
这样结果就是调用=号以后,s2地址和s1地址一样,都是0x00364ff9。
假如我们动态库有这样一个类class DLL接口:
SetString(std::
string
str)
{
m_str = str;
}
{
m_str = str;
}
在客户调用时候:
std::
string
str
=
"
wlwlxj
"
;
DLL d;
d.SetString(str); // 此时没有深拷贝,而是引用了str内部指针地址
在调用结束的时候,dll内部删除成员变量的时候,会判断m_str内部指针合法性,由于实际分配是在调用端,在dll内部自然检查指针非法。
DLL d;
d.SetString(str); // 此时没有深拷贝,而是引用了str内部指针地址
解决方法就是避免std::string引用计数,接口处修改为SetString(const char*),这样在dll内部分配内存,内部释放,就不会有问题。