看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《d630200x (DOGE)》之銘言: : 有看到有人說這樣效率比較好 : 但我自己測試來看是看不出差異(可能是我測試方式太簡單) : 就我個人來說我是覺得寫在函式裡較為美觀 : 但是很多網路上的無論是simple code還是教學,在初始化時是比較常看到單冒號的 : 請問是真的效率上差很多,還是單純風格差異而已? : ----- : Sent from JPTT on my Asus ASUS_I01WD. 這在語法還有語意上有不同的考量, 後面會舉兩個例子說明. 語法 通常初學者會有這個問題是因為使用到 SemiRegular 型別物件作為資料成員 , 如 int, double 等等 vocabulary type, 它們都有功能相仿的建構子 (constructor)operator=() 可呼叫. 不妨寫個類別實驗看看兩種寫法有 什麼差異: #include <cstdio> struct MyInt { MyInt() { puts(__PRETTY_FUNCTION__); } MyInt(int) { puts(__PRETTY_FUNCTION__); } MyInt& operator=(int) { puts(__PRETTY_FUNCTION__); return *this; } }; struct Test { Test() { i = 0; } Test(bool) : i(0) {} MyInt i; }; Test(); // print: MyInt::MyInt() // MyInt& MyInt::operator=(int) Test(true); // print: MyInt::MyInt(int) 建構子是絕對會被呼叫的函式, 因此物件的狀態若能在建構子裡面準備好, 就 不需要額外呼叫別的函式做重複的事情. 語意 資料成員/父類別也算是物件的一部分, 在它們的建構子都成功結束的前提下 , 我們才有辦法建構出完整的物件. 所以語言設計上你無法消除從資料成員/ 父類別建構子丟出的例外: #include <iostream> #include <stdexcept> struct Foo { Foo() { throw std::runtime_error("message"); } }; struct Bar { Bar() try { // constructor body } catch (std::exception& e) { std::cerr << e.what() << std::endl; // exception will be re-thrown here } Foo foo; }; 對 std::vector 這類會在獲取記憶體失敗時丟出例外的資料成員, 我們可以 用 two-phase initialization 來延後準備物件狀態, 讓物件有機會完成初始 (雖然通常呼叫建構子比較合理): #include <vector> struct Example { Example() { do { try { v.resize(10'000'000); } catch (std::bad_alloc& e) { // do something here } } while (empty(v)); // retry until success } std::vector<int> v; }; 所以風格怎樣的倒不是重點, 重要的是你要知道自己在做什麼 :) -- [P1389R1] Standing Document for SG20: Guidelines for Teaching C++ to Beginners https://wg21.link/p1389r1 SG20 Education and Recommended Videos for Teaching C++ https://www.cjdb.com.au/sg20-and-videos -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.193.76.216 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1606252263.A.77F.html
petercoin: 推一個 11/25 11:31
※ 編輯: poyenc (123.193.76.216 臺灣), 11/25/2020 11:38:46
s4300026: 推 11/25 17:41
KevinR: m 11/25 19:07
F04E: 推 11/26 10:17
deangood01: 有開優化 compiler應該還是會幫忙做 09/14 17:36