• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

Delphi字符串的引用计数与生命周期

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

先来段代码

 

type
  MyString = AnsiString;
  PMyChar = PAnsiChar;


procedure TForm2.Button2Click(Sender: TObject);
var
  p: PMyChar;
  s, s2: MyString;
begin
  self.Caption := 'frmTest';  //7位的字符串
  p := GetCaption;
  s2 := p;   //这是时候s2 为frmTes
  ShowMessage(s2);  //*****显示出来为frmTes
end;

function TForm2.GetCaption: PMyChar;
var
  s1, s2: MyString;
begin
  s2 := MyString(self.Caption);
  Result := PMyChar(MyString(s2));
end;

 

研究说明(代表个人意见)(XE下面测试)

 

function TForm2.GetCaption: PMyChar;
var
  s1: MyString;
begin
  s1 := MyString(Self.Caption);    //self.Caption源码得知,是获取了一块临时的空间(A1)
  //A1(integer(s1))

  i:= StringRefCount(s1);  //i=1

  Result := PMyChar(MyString(s1));  //Result指针指向的为(A1)的空间
  //Integer(@Result^) = A1(integer(s1))  是指向同一块空间

  i:= StringRefCount(s1);  //i=1
end;
//函数返回后s1因为是局部变量 s1的引用计数为0,integer(s1)的空间被标志为可以覆盖
//返回的为指针,不增加s1的引用计数


procedure TForm2.Button2Click(Sender: TObject);
var
  p: PMyChar;
  s, s2: MyString;
begin
  self.Caption := 'frmTest';
  p := GetCaption; //实际上p指向的那块地址被标注为可以覆盖,随时都有可能被覆盖,是很危险的
  //Integer(@p^) = GetCaption内部给s1分配的那块空间地址
 
  s2 := p;         //导致丢掉了字符..
  //因为p指向的内存是可以被覆盖的,s2分配的地址可能和p指向的地址是一样的,导致丢掉了字符..
  //Integer(s2) 可能= Integer(@p^)  测试是发现都一样

  //下面操作(SetLength)同样也会一样结果,s2占用的和p占用的同样大小(或者小)。
  //这样导致了s2分配的空间可能和p内存一样
  //如果7改成较大的数就正常
  //  SetLength(s2, 7);
  //  StrCopy(PMyChar(s2), p);

  ShowMessage(s2);  //错误
end;

 

 解决方案(1)

将s1定义为内成员变量,这样当GetCaption执行完后那块空间不会被标准为可读写

 

function TForm2.GetCaption2: PMyChar;
begin
  FMyCaption := MyString(Self.Caption);    //self.Caption源码得知,是获取了一块临时的空间(A1)
  //A1(integer(FMyCaption))

  i:= StringRefCount(FMyCaption);  //i=1

  Result := PMyChar(MyString(FMyCaption));  //Result指针指向的为(A1)的空间
  //Integer(@Result^) = A1(integer(FMyCaption))  是指向同一块空间

  i:= StringRefCount(FMyCaption);  //i=1
end;
//执行完后FMyCaption不是临时变量,指向的地址不可以被覆盖

procedure TForm2.btnGetCaption2Click(Sender: TObject);
var
  p: PMyChar;
  s, s2: MyString;
begin
  self.Caption := 'frmTest';
  p := GetCaption2; //实际上p指向的那块地址和FMyCaption的地址是一样的
  //Integer(@p^) = GetCaption2内部给FMyCaption分配的那块空间地址是一样

  s2 := p;
  //因为p指向的内存是不可以被覆盖的,s2分配的地址不可可能和p指向的地址是一样的,这样做是安全的
  //Integer(s2) <> Integer(@p^)

  i:= StringRefCount(s2);  //i=1  新的内存

  ShowMessage(s2);  //正确
end;

 

 

***

局部变量

 

function TForm2.GetCaption2: PMyChar;
var

  s1: MyString;
begin
  s1 := 'frmTest'
  i:= StringRefCount(s1);  //i=-1  常量地址指向空间不可被覆盖
 
  //UniqueString(s1); 
  //i:= StringRefCount(s1);  //i=1  s1又变成临时的,函数返回后s1指向的地址不再安全
 
  Result=PMyChar(s1)
end;

 

 

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
matlab的正则表达式发布时间:2022-07-22
下一篇:
MATLAB图像处理工具箱发布时间:2022-07-22
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap