簡體   English   中英

Delphi 中的堆棧溢出

[英]Stack Overflow in Delphi

我在 StackOverflow.com 上發布了我的 Stack Overflow 問題。 最好的諷刺!

反正。 我在我的 SkypeReply 事件處理程序上調用這個過程,它被觸發了很多:

  Procedure OnCategoryRename;
  Var
    CategoryID : Integer;
    sCtgName : String;
  Begin
    if (AnsiContainsStr(pCommand.Reply,'GROUP')) and (AnsiContainsStr(pCommand.Reply,'DISPLAYNAME')) then
      begin
         sCtgName := pCommand.Reply;
         Delete(sCtgName,1,Pos('GROUP',sCtgName)+5);
         CategoryID := StrToInt(Trim(LeftStr(sCtgName,Pos(' ',sCtgName))));
         sCtgName := GetCategoryByID(CategoryID).DisplayName; // Removing THIS line does not produce a Stack Overflow!
         ShowMessage(sCtgName); 
      end;

這樣做的想法是遍歷我的 Skype 組列表,以查看已重命名的組。 AFAIK 那不重要,因為我的 SO 已被追蹤到出現在這里

Function GetCategoryByID(ID : Integer):IGroup;
Var
  I : Integer;
  Category : IGroup;
Begin
  // Make the default result nil
  Result := nil;

  // Loop thru the CUSTOM CATEGORIES of the ONLY SKYPE CONTROL used in this project
  // (which 100% positive IS attached ;) )
  for I := 1 to frmMain.Skype.CustomGroups.Count do
    Begin
      // The Category Variable
      Category := frmMain.Skype.CustomGroups.Item[I];
      // If the current category ID returned by the loop matches the passed ID
      if Category.Id = ID then
        begin
          // Return the Category as Result (IGroup)
          Result := Category;
          // Exit the function.
          Exit;
        end;
    End;
End;

當我在 Result := Category; 處設置斷點時; 和 Single Step thru,這 2 行會一遍又一遍地執行,緊隨其后!

當我注釋掉sCtgName := GetCategoryByID(CategoryID).DisplayName; 在第一個代碼片段中,沒有溢出,消息會顯示一次應該的。 但是, GetCategoryByID是我寫的一個函數,我也寫了一個類似的函數,它工作得很好(GetCategoryByName),所以我不明白為什么它決定重復

// Return the Category as Result (IGroup)
Result := Category;
// Exit the function.
Exit;

一遍又一遍。

編輯:這是您如何重現它: https : //gist.github.com/813389

編輯:這是我的 CallStack,根據要求:調用堆棧

編輯2:更多信息:更多信息

確保在關閉“優化”、“堆棧幀”和“使用調試 .dcu”的情況下編譯您的項目,以獲得最詳細的調用堆棧。 然后在此處發布您遇到堆棧溢出時獲得的調用堆棧(如果您無法從中識別問題的性質)。

無限遞歸可能會導致堆棧溢出。

當您編寫包含事件處理程序的代碼時,您必須非常小心。 正如大衛所說,你可以做的一件事是幫助你調試它,而不是跳過這樣的調用。 F7 進入呼叫。

您可以做的另一件事是在函數 GetCategoryById 的頂部放置一個斷點。 現在看看你的調用堆棧。 你看到堆棧中重復的名字了嗎? 這應該說得很清楚了。

您的問題中沒有顯示的內容:您在此處發布的“OnCategoryRename”函數是從“TForm.Skype1Reply”回調調用的子函數。

要看到這一點,我必須單擊您的 github 鏈接 - 但我認為這是您問題的一個重點。

我的猜測:

  • 您的“GetCategoryById”函數實際上發送了一個查詢,它會觸發“Skype1Reply”。
  • 如果組名已更改,“Skype1Reply”將調用“OnCategoryRename”。
  • “OnCategoryRename”調用“GetCategoryById”
  • “GetCategoryById”觸發“Skype1Reply”
  • 不知何故,測試說“如果組名已更改”仍然是正確的,因此“Skype1Reply”調用“OnCategoryRename”
  • “OnCategoryRename”調用“GetCategoryById”
  • 沖洗,重復

我認為一個快速而骯臟的解決方法是改變

sCtgName := GetCategoryByID(CategoryID).DisplayName; // Removing THIS line does not produce a Stack Overflow!

sCtgName := //find another way to get the new name, which you can probably get from your ICommand object
            pCommand.Reply.ReadDataFromReplyAndGetNewDisplayName;

將來,我建議您針對此類問題發布完整的代碼示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM