先来段代码
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;
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论