在輸入main之前調用全局聲明類的構造函數。雖然這可能會讓代碼的新讀者感到困惑,因爲它很少完成,是不是一個好主意?在C++中,編寫在main()之前執行的代碼是否是一種好的形式?
回答
這不是必然一個壞主意,但通常,是的。
首先,它是全局數據,全局數據通常是一件壞事。 您擁有的全球化程度越高,您對程序的推理就越難。其次,C++不保證以不同的翻譯單位(.cpp文件)定義的靜態對象的初始化順序 - 所以如果它們相互依賴,則可能會遇到麻煩。
如果代碼會影響在其他文件中聲明的變量,你可能比初始化爲了更大的問題。如果在文件中定義的函數或變量沒有直接用於程序中的其他地方,鏈接器可能會丟棄整個編譯單元,包括初始化代碼。 (這是如果該文件是通過掛鉤或由全球建築安裝註冊表使用的問題。) – 2010-06-24 14:56:48
此外,全局的線程是不安全的,至少可以說和訪問它們是緩慢的(甚至訪問堆更快)。在絕大多數廣闊的案例中,全局都是一個壞主意。當然也有例外。 – Puppy 2010-06-24 21:13:41
構造函數不依賴於順序並進行一些良性的初始化。線程被仔細控制。 – Bruce 2010-06-25 00:35:05
除了有問題的形式 - 它不會移植到某些平臺。
正如你指出的那樣,它是允許的。在我工作的最後一家公司,當出現這種情況時,我們制定了一項政策,向main()添加一個適當的註釋,以表明它適用於哪些變量。如果你的情況不好,儘量做到最好。
是的,這是不好的。由於您無法捕獲異常並處理它們,因此將使用默認處理程序。在C++那意味着調用終止...
例如:內容a.cpp
輸出的
#include <stdexcept>
int f() { throw std::runtime_error("boom"); return 42; }
int i = f();
int main(int argc, char* argv[])
{
return 0;
}
:g++ a.cpp && ./a.out
terminate called after throwing an instance of 'std::runtime_error'
what(): boom
Aborted (core dumped)
您可以在主試加一個try ... catch
,那也不會幫助。
編輯:賈爾夫的觀點也有效。聽聽他的建議。
main()try {...} catch(...){...}怎麼樣? – 2010-06-24 15:02:08
我不認爲這個例子是合法的,因爲'int i = f();'。據我所知,你不能在聲明一個全局變量時調用一個函數。 – 2010-06-24 15:12:01
@Alexandre - 我們正在討論名爲BEFORE主要開始的代碼。因此,main中的try/catch不能達到它,因爲執行此代碼時沒有輸入try。 – 2010-06-24 15:14:08
使用具有不平凡的構造函數和析構函數的全局/靜態對象是可怕的。我看到足夠多的巨大軟件項目因爲全局/靜態對象和單例的不受控制的使用而陷入災難。
問題不在於它是在main
之外運行的代碼。就是那些物體是以無法控制的順序構建和銷燬的。
另外我認爲這是一個普遍不好的做法,無論如何使用全局變量(即使是普通變量),但有一些例外。 每一段代碼都應該在一個定義良好的上下文中運行,並且所有的變量都應該屬於它。
它不壞形式在所有,它不是混亂。靜態初始化是該語言的一個有意的特徵。在需要時使用它。與全局相同。在需要時使用它們。像任何功能,知道何時是適當和了解它的侷限性是成爲一個強大的程序員組成部分。
壞形式的重組,否則完全沒有計劃,只是爲了避免全局或靜態初始化。
這種假設你正在處理一個已經寫好的項目;原來的問題實際上是規定性的,而不是評估性的。 – 2010-06-24 19:13:13
我會走得這麼遠,說這是不好的形式對非吊艙,特別是如果你在一個團隊中,因爲可以很容易地從這個出現初始化順序問題主要是工作。
// the following invokes undefined behavior.
static bool success=cout<<"hello world\n";
人們通常不會像上面那樣編寫代碼,但要考慮成功是否被初始化爲另一個函數的返回值。現在有人試圖在該函數中使用cout或cerr或任何其他全局對象調用相同的未定義行爲。
對於構造函數和析構函數用戶定義類型,考慮替代的方法,其中訪問初始化:
static Foo& safe_static()
{
static Foo f;
return f;
}
不幸的是,這也與線程安全的問題,所以需要建設某種鎖定機構'f',如果你正在同時訪問safe_static。
這就是說,我不認爲一個人應該儘量保持簡單。不幸的是,當涉及到在文件範圍定義的用戶定義的對象時,很容易陷入未定義的行爲。需要額外的努力來寫上面的東西safe_static可以防止很多頭痛。
例外的是另一點。如果你的靜態對象拋出它們的構造函數,那麼你無法捕捉異常。如果你希望你的應用程序非常健壯,甚至可以處理啓動錯誤,那麼你必須仔細地構造代碼(例如:在構造函數中爲你在文件範圍創建的對象設置try/catch塊,以避免引發異常在ctor之外,也避免了拋出的初始化列表)。
如果你在一個團隊中工作,你可能會想:「哦,我沒有訪問我班上的其他全局變量,我不妨在文件範圍內使用一個簡單的全局內部鏈接。 「這可能是真的,但在你知道它之前,你的同事會添加另一個全局變量並嘗試從你的類的構造函數中訪問它。突然之間,你有未定義的行爲,甚至可能不會顯示爲主要平臺上的問題,只是當你試圖將代碼移植到別處時,你的代碼纔會崩潰並做其他奇怪的事情。
這真的不值得的潛在頭痛IMO,以及它是更容易避免,而不是解決問題。
- 1. 在main()之前執行代碼()
- 2. 您是否在編碼之前用僞代碼寫出算法?
- 3. 在一個類中編寫所有數據庫訪問代碼是否是一種好的做法?
- 4. 編寫Scala代碼時忽略點和括號是否是一種好習慣?
- 5. 在執行Jenkinsfile之前執行代碼
- 6. 在Perl腳本結束之前總是執行一些代碼
- 7. 在html中編寫JavaScript代碼是否好?
- 8. 在z3 C++接口中是否存在一種bitvector concat形式?
- 9. 是否可以在Libgdx中編寫C/C++代碼?
- 10. 如何在VC中進入main()例程之前執行一些代碼?
- 11. 在代碼之前執行的Response.Redirect
- 12. JavaScript中的提示對話框在之前編寫的代碼之前運行
- 13. 是否有可能在執行客戶端代碼之前執行服務器端代碼在ASP.Net
- 14. 是否有可能在C++中的return語句之後執行代碼?
- 15. 在函數之後執行代碼之前是否完成了for循環?
- 16. 有沒有更好的方式在C#3.0中編寫這行C#代碼?
- 17. 是否可以在C#中運行時創建/執行代碼?
- 18. 在Javascript中,是否有一種技術可以在返回後執行代碼?
- 19. 在執行Android的代碼,它播種異常線程 「main」 java.lang.ExceptionInInitializerError
- 20. IOS在main()之前執行什麼?
- 21. 在UIAlertController被解除之前是否可以阻止執行我的代碼?
- 22. 是我爲sparql執行寫的代碼是否正確?
- 23. 爲什麼一個類的+ load()在objc的main()之前執行?
- 24. 在頁面加載之前執行代碼的最佳方式是什麼
- 25. 在內部使用的代碼中製作額外的代碼是否是一種好的做法?
- 26. Ajax ModalPopUp擴展在執行之前的代碼之前彈出的代碼
- 27. 我有一個C++代碼,在執行main()之前在啓動時崩潰,問題可能出現在哪裏?
- 28. 代碼在API響應之前執行
- 29. 在main()執行之前實例化一個類的對象
- 30. 在scala中編寫main的最佳方式是什麼?
每次使用全局變量時,上帝殺死一隻小貓。 – ereOn 2010-06-24 14:48:40
不,我不..... – 2010-06-24 15:58:19
你不這樣做,但我.... – 2010-06-25 01:56:07