@SebastianRedl ได้ให้คำตอบที่ตรงไปตรงมาแล้ว แต่คำอธิบายพิเศษบางอย่างอาจมีประโยชน์
TL; DR = มีกฎสไตล์เพื่อให้คอนสตรัคเตอร์เรียบง่ายมีเหตุผลสำหรับมัน แต่เหตุผลเหล่านั้นส่วนใหญ่เกี่ยวข้องกับรูปแบบการเข้ารหัสในอดีต (หรือแย่มาก) การจัดการข้อยกเว้นในตัวสร้างมีการกำหนดไว้อย่างดีและ destructors จะยังคงถูกเรียกใช้สำหรับตัวแปรและสมาชิกในท้องถิ่นที่สร้างขึ้นอย่างสมบูรณ์ซึ่งหมายความว่าไม่ควรมีปัญหาใด ๆ ในรหัสภาษา C ++ กฎสไตล์ยังคงมีอยู่ แต่โดยปกติแล้วไม่ใช่ปัญหา - การเริ่มต้นทั้งหมดไม่จำเป็นต้องอยู่ในตัวสร้างและโดยเฉพาะอย่างยิ่งไม่จำเป็นต้องมีตัวสร้าง
เป็นกฎสไตล์ทั่วไปที่ผู้สร้างควรทำอย่างน้อยที่สุดที่พวกเขาสามารถทำได้เพื่อตั้งค่าสถานะที่ถูกต้องที่กำหนดไว้ หากการเริ่มต้นของคุณมีความซับซ้อนมากขึ้นก็ควรได้รับการจัดการนอกนวกรรมิก หากไม่มีค่าเริ่มต้นที่ถูกต้องที่ตัวสร้างของคุณสามารถตั้งค่าได้คุณควรทำให้ผู้บุกรุกที่บังคับใช้เรียนลดค่าลง ตัวอย่างเช่นหากการจัดสรรพื้นที่เก็บข้อมูลสำหรับคลาสของคุณเพื่อจัดการมีราคาแพงเกินไปให้เพิ่มสถานะที่ยังไม่ได้จัดสรร แต่เป็นโมฆะเนื่องจากแน่นอนว่ามีสถานะกรณีพิเศษเช่น null ไม่เคยทำให้เกิดปัญหาใด ๆ เสียงกระแอม
แม้ว่าจะพบเห็นได้ทั่วไปในรูปแบบสุดโต่งนี้มันไกลเกินกว่าที่แน่นอน โดยเฉพาะอย่างยิ่งการถากถางของฉันบ่งบอกว่าฉันอยู่ในค่ายที่บอกว่าค่าคงที่ที่ไม่แน่นอนมักจะมีราคาสูงเกินไป อย่างไรก็ตามมีเหตุผลที่อยู่เบื้องหลังกฎสไตล์และมีวิธีที่จะมีทั้งตัวสร้างน้อยที่สุดและค่าคงที่ที่แข็งแกร่ง
เหตุผลที่เกี่ยวข้องกับการล้าง destructor อัตโนมัติโดยเฉพาะอย่างยิ่งในการเผชิญกับข้อยกเว้น โดยทั่วไปจะต้องมีจุดที่กำหนดชัดเจนเมื่อคอมไพเลอร์กลายเป็นผู้รับผิดชอบในการเรียก destructors ในขณะที่คุณยังอยู่ในการเรียก constructor วัตถุไม่จำเป็นต้องถูกสร้างอย่างสมบูรณ์ดังนั้นจึงไม่สามารถเรียก destructor สำหรับวัตถุนั้นได้ ดังนั้นความรับผิดชอบในการทำลายวัตถุจะถ่ายโอนไปยังคอมไพเลอร์เท่านั้นเมื่อตัวสร้างเสร็จสมบูรณ์ สิ่งนี้เรียกว่า RAII (การจัดสรรทรัพยากรเป็นการเริ่มต้น) ซึ่งไม่ใช่ชื่อที่ดีที่สุด
try .. catch
ถ้าโยนยกเว้นเกิดขึ้นภายในตัวสร้างสิ่งที่ตอบสนองความต้องการส่วนสร้างขึ้นมาเพื่อทำความสะอาดได้อย่างชัดเจนขึ้นโดยทั่วไปใน
อย่างไรก็ตามส่วนประกอบของวัตถุที่สร้างขึ้นเรียบร้อยแล้วนั้นเป็นความรับผิดชอบของคอมไพเลอร์อยู่แล้ว ซึ่งหมายความว่าในทางปฏิบัติมันไม่ได้เป็นเรื่องใหญ่ เช่น
classname (args) : base1 (args), member2 (args), member3 (args)
{
}
เนื้อความของตัวสร้างนี้ว่างเปล่า ตราบใดที่การก่อสร้างสำหรับbase1
, member2
และmember3
มีความปลอดภัยยกเว้นมีอะไรที่จะต้องกังวลเกี่ยวกับการเป็น ตัวอย่างเช่นหากตัวสร้างการmember2
โยนตัวสร้างนั้นมีหน้าที่ทำความสะอาดตัวเอง ฐานbase1
สร้างเสร็จสมบูรณ์แล้วดังนั้นตัวทำลายจะถูกเรียกโดยอัตโนมัติ member3
ไม่เคยถูกสร้างขึ้นมาเพียงบางส่วนดังนั้นจึงไม่จำเป็นต้องทำความสะอาด
แม้ว่าจะมีร่างกาย แต่ตัวแปรท้องถิ่นที่สร้างขึ้นอย่างสมบูรณ์ก่อนที่จะถูกโยนทิ้งยกเว้นจะถูกทำลายโดยอัตโนมัติเช่นเดียวกับฟังก์ชั่นอื่น ๆ ตัวสร้างที่เล่นปาหี่ตัวชี้ดิบหรือ "เจ้าของ" บางชนิดของสถานะโดยปริยาย (เก็บไว้ที่อื่น) - โดยทั่วไปหมายถึงการเริ่มต้น / รับฟังก์ชั่นการโทรจะต้องจับคู่กับปลาย / ปล่อยเรียก - อาจทำให้เกิดปัญหาความปลอดภัยยกเว้น ไม่สามารถจัดการทรัพยากรได้อย่างเหมาะสมผ่านคลาส ตัวอย่างเช่นถ้าคุณเปลี่ยนพอยน์เตอร์พอยน์เตอร์ด้วยunique_ptr
ในตัวสร้างคอนสตรัคเตอร์สำหรับunique_ptr
จะถูกเรียกโดยอัตโนมัติหากจำเป็น
ยังมีเหตุผลอื่น ๆ ที่ผู้คนเลือกใช้สิ่งก่อสร้างที่ต้องทำขั้นต่ำ หนึ่งเป็นเพราะกฎสไตล์มีอยู่หลายคนคิดว่าการโทรคอนสตรัคเตอร์นั้นมีราคาถูก วิธีหนึ่งที่จะมีได้ แต่ยังคงมีค่าคงที่ที่แข็งแกร่งคือการมีคลาสโรงงาน / ผู้สร้างแยกต่างหากที่มีค่าคงที่ที่อ่อนแอแทนและตั้งค่าเริ่มต้นที่จำเป็นโดยใช้การเรียกสมาชิกฟังก์ชันปกติ เมื่อคุณมีสถานะเริ่มต้นที่คุณต้องการให้ส่งผ่านวัตถุนั้นเป็นอาร์กิวเมนต์ไปยังตัวสร้างสำหรับคลาสด้วยค่าคงที่ที่แข็งแกร่ง นั่นสามารถ "ขโมยความกล้า" ของวัตถุที่ไม่แปรเปลี่ยนได้ - ย้ายซีแมนทิกส์ - ซึ่งเป็นการดำเนินการที่ถูก (และมักจะnoexcept
)
และแน่นอนว่าคุณสามารถสรุปได้ในmake_whatever ()
ฟังก์ชั่นดังนั้นผู้โทรของฟังก์ชันนั้นไม่จำเป็นต้องดูอินสแตนซ์ของคลาสที่ไม่เปลี่ยนแปลง