Delphi字串的引用計數與生命週期
先來段程式碼
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下面測試)
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分配的那塊空間地址
//因為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執行完後那塊空間不會被標準為可讀寫
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;
***
區域性變數
var
s1: MyString;
begin
i:= StringRefCount(s1); //i=-1 常量地址指向空間不可被覆蓋
//i:= StringRefCount(s1); //i=1 s1又變成臨時的,函式返回後s1指向的地址不再安全
end;
相關文章
- View生命週期與Activity生命週期的關係View
- Javascript 變數生命週期JavaScript變數
- MVN命令與生命週期
- Servlet生命週期與方法Servlet
- ASP.NET頁面生命週期與應用程式生命週期ASP.NET
- React的生命週期與應用React
- Go語言變數的生命週期Go變數
- 生命週期
- 細說 rust 生命週期引數Rust
- Flutter 的生命週期Flutter
- SQL的生命週期SQL
- Laravel的生命週期Laravel
- vue的生命週期Vue
- Fragment的生命週期Fragment
- App的生命週期APP
- View的生命週期View
- Servlet的生命週期Servlet
- bean的生命週期Bean
- C++臨時變數的生命週期C++變數
- Activity生命週期與啟動模式模式
- PHP 生命週期PHP
- Flutter - 生命週期Flutter
- sessionStorag 生命週期Session
- Fragment生命週期Fragment
- Activity生命週期
- vue - 生命週期Vue
- React生命週期React
- ubuntu生命週期Ubuntu
- React 生命週期React
- vue生命週期Vue
- 品牌生命週期和產品生命週期之間的關係
- ES6 變數作用域與提升:變數的生命週期詳解變數
- Salesforce 生命週期管理(一)應用生命週期淺談Salesforce
- React新的生命週期React
- iOS APP的生命週期iOSAPP
- Java 物件的生命週期Java物件
- Vue生命週期的理解Vue
- [React]元件的生命週期React元件