คำสั่งอะไร
return {};
ใน C ++ 11 ระบุและเมื่อใดควรใช้แทน (พูด)
return NULL;
หรือ
return nullptr;
return;
โดยไม่มีค่า?
return;
ในทางกลับกันreturn{};
ก็ใช้ได้หากคุณมีประเภทการส่งคืน
คำสั่งอะไร
return {};
ใน C ++ 11 ระบุและเมื่อใดควรใช้แทน (พูด)
return NULL;
หรือ
return nullptr;
return;
โดยไม่มีค่า?
return;
ในทางกลับกันreturn{};
ก็ใช้ได้หากคุณมีประเภทการส่งคืน
คำตอบ:
return {};
ระบุว่า "ส่งคืนอ็อบเจ็กต์ของประเภทการส่งคืนของฟังก์ชันที่เริ่มต้นด้วยรายการเริ่มต้นที่ว่างเปล่า" พฤติกรรมที่แน่นอนขึ้นอยู่กับชนิดของวัตถุที่ส่งคืน
จากcppreference.com (เนื่องจาก OP ถูกแท็ก C ++ 11 ฉันจึงไม่รวมกฎใน C ++ 14 และ C ++ 17 โปรดดูลิงค์สำหรับรายละเอียดเพิ่มเติม):
- ถ้า braced-init-list ว่างเปล่าและ T เป็นประเภทคลาสที่มีตัวสร้างเริ่มต้นการกำหนดค่าเริ่มต้นจะดำเนินการ
- มิฉะนั้นหาก T เป็นประเภทการรวมการเริ่มต้นแบบรวมจะดำเนินการ
- มิฉะนั้นถ้า T เป็นความเชี่ยวชาญเฉพาะของ std :: initializer_list อ็อบเจ็กต์ T จะถูกกำหนดค่าเริ่มต้นโดยตรงหรือ copy-initialized ขึ้นอยู่กับบริบทจาก braced-init-list
มิฉะนั้นจะพิจารณาตัวสร้างของ T ในสองขั้นตอน:
- ตัวสร้างทั้งหมดที่ใช้ std :: initializer_list เป็นอาร์กิวเมนต์เดียวหรือเป็นอาร์กิวเมนต์แรกหากอาร์กิวเมนต์ที่เหลือมีค่าดีฟอลต์จะถูกตรวจสอบและจับคู่โดยการแก้ปัญหาโอเวอร์โหลดกับอาร์กิวเมนต์เดียวประเภท std :: initializer_list
- หากขั้นตอนก่อนหน้าไม่เกิดการจับคู่ตัวสร้างทั้งหมดของ T จะมีส่วนร่วมในการแก้ปัญหาโอเวอร์โหลดกับชุดของอาร์กิวเมนต์ที่ประกอบด้วยองค์ประกอบของ braced-init-list โดยมีข้อ จำกัด ที่อนุญาตให้ใช้เฉพาะการแปลงที่ไม่ จำกัด เท่านั้น หากขั้นตอนนี้สร้างตัวสร้างที่ชัดเจนเป็นตัวสร้างที่เหมาะสมที่สุดสำหรับการเริ่มต้นรายการคัดลอกการคอมไพล์จะล้มเหลว (หมายเหตุในการเริ่มต้นการคัดลอกอย่างง่ายจะไม่พิจารณาตัวสร้างที่ชัดเจนเลย)
มิฉะนั้น (ถ้า T ไม่ใช่ประเภทคลาส) หาก braced-init-list มีเพียงองค์ประกอบเดียวและ T ไม่ใช่ประเภทอ้างอิงหรือเป็นประเภทอ้างอิงที่เข้ากันได้กับประเภทขององค์ประกอบ T จะตรง - initialized (in direct-list-initialization) หรือ copy-initialized (in copy-list-initialization) ยกเว้นว่าไม่อนุญาตให้ จำกัด การแปลงให้แคบลง
- มิฉะนั้นหาก T เป็นประเภทการอ้างอิงที่ไม่เข้ากันกับประเภทขององค์ประกอบ (สิ่งนี้จะล้มเหลวหากการอ้างอิงเป็นการอ้างอิง lvalue ที่ไม่ใช่ const)
- มิฉะนั้นถ้า braced-init-list ไม่มีองค์ประกอบ T คือค่าเริ่มต้น
ก่อน C ++ 11 สำหรับฟังก์ชันที่ส่งคืน a std::string
คุณจะต้องเขียน:
std::string get_string() {
return std::string();
}
การใช้ไวยากรณ์รั้งใน C ++ 11 คุณไม่จำเป็นต้องทำซ้ำประเภท:
std::string get_string() {
return {}; // an empty string is returned
}
return NULL
และreturn nullptr
ควรใช้เมื่อฟังก์ชันส่งคืนประเภทตัวชี้:
any_type* get_pointer() {
return nullptr;
}
อย่างไรก็ตามNULL
เลิกใช้งานตั้งแต่ C ++ 11 เนื่องจากเป็นเพียงนามแฝงของค่าจำนวนเต็ม (0) ในขณะที่nullptr
เป็นประเภทตัวชี้จริง:
int get_int() {
return NULL; // will compile, NULL is an integer
}
int get_int() {
return nullptr; // error: nullptr is not an integer
}
สิ่งนี้อาจสับสน:
int foo()
{
return {}; // honestly, just return 0 - it's clearer
}
นี่อาจไม่ใช่:
SomeObjectWithADefaultConstructor foo()
{
return {};
// equivalent to return SomeObjectWithADefaultConstructor {};
}
initializer_list
สร้างจะไม่ใช้หากไม่มีตัวสร้างเริ่มต้น
return {}
ไม่เทียบเท่าreturn SomeObjectWithADefaultConstructor{};
return {};
หมายความว่า{}
เป็นค่าเริ่มต้นสำหรับค่าตอบแทน ค่าที่ส่งคืนเป็นรายการเริ่มต้นด้วยรายการว่าง
นี่คือพื้นหลังบางส่วนของค่าส่งคืนโดยอ้างอิงจาก [stmt.return] ในมาตรฐาน C ++:
สำหรับฟังก์ชั่นที่ให้ผลตอบแทนตามมูลค่า (เช่นพิมพ์กลับไม่ใช่การอ้างอิงและไม่ได้void
) มีวัตถุชั่วคราวที่เรียกว่าค่าตอบแทน วัตถุนี้สร้างขึ้นโดยreturn
คำสั่งและตัวเริ่มต้นขึ้นอยู่กับสิ่งที่อยู่ในคำสั่ง return
ค่าที่ส่งคืนจะคงอยู่จนถึงจุดสิ้นสุดของนิพจน์แบบเต็มในรหัสที่เรียกใช้ฟังก์ชัน หากมีประเภทคลาสตัวทำลายจะทำงานเว้นแต่ว่าจะมีการขยายอายุการใช้งานโดยผู้เรียกเชื่อมโยงการอ้างอิงโดยตรงกับมัน
ค่าที่ส่งคืนสามารถเริ่มต้นได้สองวิธี:
return some_expression;
- ค่าตอบแทนที่มีการคัดลอกเริ่มต้นจากsome_expression
return { possibly_empty_list };
- ค่าที่ส่งคืนจะ
เริ่มต้นจากรายการสมมติว่าT
เป็นประเภทการส่งคืนของฟังก์ชันจากนั้นสังเกตว่าreturn T{};
แตกต่างจากreturn {}
: ในอดีตชั่วคราวT{}
จะถูกสร้างขึ้นจากนั้นค่าที่ส่งคืนจะถูกคัดลอกเริ่มต้นจากชั่วคราวนั้น
สิ่งนี้จะล้มเหลวในการคอมไพล์หากT
ไม่มี copy / move-constructor ที่สามารถเข้าถึงได้ แต่return {};
จะทำได้สำเร็จแม้ว่าจะไม่มีตัวสร้างเหล่านั้นก็ตาม ดังนั้นreturn T{};
อาจแสดงผลข้างเคียงของตัวสร้างสำเนา ฯลฯ แม้ว่านี่จะเป็นบริบทการคัดลอกสำเนาดังนั้นจึงอาจไม่ได้
นี่คือสรุปสั้น ๆ เกี่ยวกับการเริ่มต้นรายการใน C ++ 14 (N4140 [dcl.init.list] / 3) โดยที่ initializer เป็นรายการว่าง:
T
เป็นการรวมสมาชิกแต่ละคนจะเริ่มต้นจากวงเล็บปีกกาหรือเท่ากับค่าเริ่มต้นหากมีหรือ{}
ใช้ขั้นตอนเหล่านี้ซ้ำT
เป็นประเภทคลาสที่มีคอนสตรัคเตอร์ดีฟอลต์ที่ผู้ใช้ระบุคอนสตรัคเตอร์นั้นจะถูกเรียกT
เป็นประเภทคลาสที่มีคอน= default
สตรัคเตอร์ที่กำหนดโดยนัยหรือed ดีฟอลต์อ็อบเจ็กต์จะถูกกำหนดค่าเริ่มต้นเป็นศูนย์จากนั้นคอนสตรัคเตอร์เริ่มต้นจะถูกเรียกใช้T
เป็น a std::initializer_list
ค่าที่ส่งคืนจะเป็นรายการว่างเปล่าT
คือเป็นประเภทที่ไม่ใช่คลาส - ชนิดที่ส่งคืนไม่สามารถเป็นอาร์เรย์ได้) ค่าที่ส่งคืนจะเริ่มต้นเป็นศูนย์{}
ซึ่งอาจเป็นค่าเริ่มต้นหรือไม่ก็ได้
เป็นเครื่องมือสั้น ๆ สำหรับอินสแตนซ์ใหม่ของประเภทการส่งคืนวิธีการ