ในความคิดของฉันอันตรายของ C ++ ค่อนข้างพูดเกินจริง
อันตรายที่สำคัญคือ: ในขณะที่ C # ช่วยให้คุณสามารถดำเนินการตัวชี้ "ไม่ปลอดภัย" โดยใช้unsafe
คำหลัก C ++ (ส่วนใหญ่จะเป็น superset ของ C) จะช่วยให้คุณใช้ตัวชี้เมื่อใดก็ตามที่คุณรู้สึกว่ามัน นอกเหนือจากอันตรายปกติที่เกิดขึ้นจากการใช้พอยน์เตอร์ (ซึ่งเหมือนกันกับ C) เช่นการรั่วไหลของหน่วยความจำบัฟเฟอร์โอเวอร์โฟลว์พอยน์เตอร์ห้อยตอม ฯลฯ C ++ แนะนำวิธีการใหม่ ๆ
"เชือกพิเศษ" นี้เพื่อที่จะพูดซึ่งโจเอล Spolsky พูดถึงโดยทั่วไปมาถึงสิ่งหนึ่ง: การเขียนชั้นเรียนที่ภายในจัดการหน่วยความจำของตัวเองหรือที่เรียกว่า " กฎ 3 " (ซึ่งตอนนี้สามารถเรียกว่ากฎ ของ 4 หรือกฎ 5 ใน C ++ 11) ซึ่งหมายความว่าหากคุณต้องการเขียนคลาสที่จัดการการจัดสรรหน่วยความจำของตัวเองภายในคุณต้องรู้ว่าคุณกำลังทำอะไรอยู่มิฉะนั้นโปรแกรมของคุณอาจมีปัญหา คุณต้องสร้าง Constructor คัดลอก Constructor, Destructor และ Operator อย่างระมัดระวังซึ่งเป็นเรื่องง่ายที่จะเกิดความผิดพลาดซึ่งมักจะทำให้เกิดความผิดพลาดที่แปลกประหลาดที่รันไทม์
อย่างไรก็ตามในความเป็นจริงการเขียนโปรแกรม C ++ ทุกวันเป็นเรื่องยากมากที่จะเขียนคลาสที่จัดการหน่วยความจำของตัวเองดังนั้นจึงทำให้เข้าใจผิดว่าโปรแกรมเมอร์ C ++ จำเป็นต้องมี "ระวัง" เสมอเพื่อหลีกเลี่ยงข้อผิดพลาดเหล่านี้ โดยปกติแล้วคุณจะทำสิ่งที่ชอบมากขึ้น:
class Foo
{
public:
Foo(const std::string& s)
: m_first_name(s)
{ }
private:
std::string m_first_name;
};
คลาสนี้ดูใกล้เคียงกับสิ่งที่คุณทำใน Java หรือ C # - ไม่ต้องการการจัดการหน่วยความจำอย่างชัดเจน (เนื่องจากคลาสไลบรารีstd::string
จะดูแลทุกอย่างโดยอัตโนมัติ) และไม่จำเป็นต้องใช้สิ่ง "Rule of 3" ตั้งแต่เริ่มต้น ตัวสร้างการคัดลอกและผู้ประกอบการที่ได้รับมอบหมายเป็นเรื่องปกติ
เมื่อคุณพยายามทำสิ่งที่ชอบเท่านั้น:
class Foo
{
public:
Foo(const char* s)
{
std::size_t len = std::strlen(s);
m_name = new char[len + 1];
std::strcpy(m_name, s);
}
Foo(const Foo& f); // must implement proper copy constructor
Foo& operator = (const Foo& f); // must implement proper assignment operator
~Foo(); // must free resource in destructor
private:
char* m_name;
};
ในกรณีนี้มันอาจเป็นเรื่องยากสำหรับมือใหม่ที่จะได้รับการมอบหมาย destructor และคัดลอกคอนสตรัคที่ถูกต้อง แต่สำหรับกรณีส่วนใหญ่ไม่มีเหตุผลที่จะทำเช่นนี้ c ++ ทำให้มันง่ายมากที่จะหลีกเลี่ยงคู่มือการจัดการหน่วยความจำ 99% ของเวลาเรียนโดยใช้ห้องสมุดเหมือนและstd::string
std::vector
ปัญหาที่เกี่ยวข้องอีกประการหนึ่งคือการจัดการหน่วยความจำด้วยตนเองในลักษณะที่ไม่คำนึงถึงความเป็นไปได้ของข้อยกเว้นที่เกิดขึ้น ชอบ:
char* s = new char[100];
some_function_which_may_throw();
/* ... */
delete[] s;
ถ้าsome_function_which_may_throw()
จริงจะโยนยกเว้นคุณจะทิ้งให้อยู่กับหน่วยความจำรั่วเพราะหน่วยความจำที่จัดสรรไว้สำหรับs
จะไม่ถูกยึด แต่ในทางกลับกันในทางปฏิบัติมันแทบจะไม่มีปัญหาอีกต่อไปด้วยเหตุผลเดียวกับที่ว่า "กฎ 3 ข้อ" ไม่ใช่ปัญหาอีกต่อไปแล้ว มันยากมาก (และโดยปกติไม่จำเป็น) เพื่อจัดการหน่วยความจำของคุณด้วยพอยน์เตอร์ เพื่อหลีกเลี่ยงปัญหาข้างต้นสิ่งที่คุณต้องทำคือใช้std::string
หรือstd::vector
และตัวทำลายจะถูกเรียกใช้โดยอัตโนมัติในระหว่างการคลี่คลายคลี่คลายหลังจากโยนข้อยกเว้น
ดังนั้นชุดรูปแบบทั่วไปที่นี่คือคุณลักษณะ C ++ จำนวนมากซึ่งไม่ได้รับมาจาก C เช่นการเริ่มต้น / ทำลายอัตโนมัติคัดลอกตัวสร้างและข้อยกเว้นบังคับให้โปรแกรมเมอร์ต้องระมัดระวังเป็นพิเศษเมื่อทำการจัดการหน่วยความจำด้วยตนเองใน C ++ แต่อีกครั้งนี่เป็นปัญหาถ้าคุณตั้งใจจะจัดการหน่วยความจำด้วยตนเองในตอนแรกซึ่งแทบจะไม่จำเป็นอีกต่อไปเมื่อคุณมีคอนเทนเนอร์มาตรฐานและพอยน์เตอร์อัจฉริยะ
ดังนั้นในความคิดของฉันในขณะที่ C ++ ให้เชือกเสริมจำนวนมากกับคุณมันแทบจะไม่จำเป็นเลยที่จะใช้มันในการแขวนคอตัวเองและข้อผิดพลาดที่ Joel พูดถึงเป็นเรื่องง่ายที่จะหลีกเลี่ยงใน C ++ สมัยใหม่
Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.
. ฉันเชื่อว่าสิ่งนี้มีคุณสมบัติเป็นคำถามดังกล่าว ...