跳轉到內容

C++ 程式設計

來自華夏公益教科書,開放書籍,開放世界

goto 關鍵字不鼓勵使用,因為它使得難以追蹤程式邏輯,從而導致錯誤。goto 語句導致當前執行執行緒跳轉到指定的標籤。

語法
label:
  statement(s);

goto label;

在一些罕見情況下,goto 語句允許編寫整潔的程式碼,例如,在處理多個退出點導致函式退出時的清理程式碼時(並且異常處理或物件解構函式不是更好的選擇)。除了這些罕見情況,無條件跳轉的使用通常是複雜設計的徵兆,因為存在多層巢狀語句。

在例外情況下,例如在進行大量最佳化時,程式設計師可能需要對程式碼行為有更多控制;goto 允許程式設計師指定執行流直接且無條件地跳轉到所需的標籤。標籤 是在函式中其他地方給標籤語句起的名稱。

注意
軟體工程領域有一篇由 W. A. Wulf 撰寫的經典論文,名為 "反對 GOTO 的論據",於 1972 年 10 月在第 25 屆 ACM 全國會議上發表,當時關於 goto 語句的爭論達到了頂峰。在這篇論文中,Wulf 認為 goto 語句應該被視為危險。Wulf 還以他對效率的評論而聞名:“在效率的名義下(不一定能真正實現效率)所犯的程式設計錯誤比任何其他原因都要多——包括盲目的愚蠢。”

例如,goto 可以用來跳出兩個巢狀迴圈。這個例子在將第一個遇到的非零元素替換為零後跳出迴圈。

for (int i = 0; i < 30; ++i) {
  for (int j = 0; j < 30; ++j) {
    if (a[i][j] != 0) {
       a[i][j] = 0;
       goto done;
     }
  }
}
done:
/* rest of program */

雖然簡單,但它們很快就會導致程式碼難以閱讀和維護。

// snarled mess of gotos

int i = 0;
  goto test_it;
body:
  a[i++] = 0;
test_it:
  if (a[i]) 
    goto body;
/* rest of program */

比等效的

for (int i = 0; a[i]; ++i) {
  a[i] = 0;
}
/* rest of program */

Goto 通常用於效能至關重要的函式,或在機器生成的程式碼(例如由 yacc 生成的解析器)的輸出中。

goto 語句幾乎應該始終避免使用,但有一些罕見的情況可以提高程式碼的可讀性。其中一種情況是“錯誤部分”。

示例

#include <new>
#include <iostream>

...

int *my_allocated_1 = NULL;
char *my_allocated_2 = NULL, *my_allocated_3 = NULL;
my_allocated_1 = new (std::nothrow) int[500];

if (my_allocated_1 == NULL)
{  
  std::cerr << "error in allocated_1" << std::endl;
  goto error;
}

my_allocated_2 = new (std::nothrow) char[1000];

if (my_allocated_2 == NULL)
{  
  std::cerr << "error in allocated_2" << std::endl;
  goto error;
}
    
my_allocated_3 = new (std::nothrow) char[1000];

if (my_allocated_3 == NULL)
{  
  std::cerr << "error in allocated_3" <<std::endl;
  goto error;
}
return 0;
    
error:
  delete [] my_allocated_1;
  delete [] my_allocated_2;
  delete [] my_allocated_3;
  return 1;

這種結構避免了處理錯誤的來源,並且比使用控制結構的等效結構更簡潔。因此,它不易出錯。

注意
雖然上面的例子展示了 goto 的合理使用,但在實際中並不常見。異常 以更清晰、更有效和更組織的方式處理此類情況。這將在“異常處理”中詳細討論。使用 RAII 來管理資源(例如記憶體)也可以避免對上面所示的大部分顯式清理程式碼的需求。

華夏公益教科書