C ++ ทำอะไรได้ดีกว่า D


135

ฉันเพิ่งได้เรียนรู้Dและฉันเริ่มคุ้นเคยกับภาษา ฉันรู้ว่ามันให้อะไรฉันยังไม่รู้ว่าจะใช้ทุกอย่างอย่างไรและฉันก็ไม่รู้อะไรมากมายเกี่ยวกับ D สำนวนและอื่น ๆ แต่ฉันกำลังเรียนรู้

ฉันชอบ D. มันเป็นภาษาที่ดีมากในหลาย ๆ ด้านการอัพเดต C ขนาดใหญ่และทำได้ดีมาก ไม่มีคุณสมบัติใดที่ดูเหมือนว่า "ปิด" แต่จริงๆแล้วค่อนข้างดีที่คิดและออกแบบมาอย่างดี

คุณมักจะได้ยินว่า D คือสิ่งที่ C ++ ควรเป็น (ฉันทิ้งคำถามว่าจริงหรือไม่สำหรับแต่ละคนและทุกคนในการตัดสินใจด้วยตนเองเพื่อหลีกเลี่ยงสงครามเปลวไฟที่ไม่จำเป็น) ฉันเคยได้ยินจากโปรแกรมเมอร์ C ++ หลายคนว่าพวกเขาสนุกกับ D มากกว่า C ++

ตัวเองในขณะที่ฉันรู้ว่า C ฉันไม่สามารถพูดได้ว่าฉันรู้ C ++ ฉันต้องการได้ยินจากคนที่รู้ทั้ง C ++ และ D หากพวกเขาคิดว่ามีบางสิ่งที่ C ++ ทำได้ดีกว่า D เป็นภาษา (หมายถึงไม่ใช่ปกติ "มีห้องสมุดบุคคลที่สามมากกว่า" หรือ "มีทรัพยากรมากกว่า" หรือ " มีงานที่ต้องใช้ภาษา C ++ มากกว่า D ")

D ได้รับการออกแบบโดยโปรแกรมเมอร์ C ++ ที่มีทักษะสูง ( Walter BrightและAndrei Alexandrescuด้วยความช่วยเหลือของชุมชน D) เพื่อแก้ไขปัญหาต่างๆที่ C ++ มี แต่มีบางสิ่งที่ไม่ได้ดีขึ้นจริงหรือ? บางอย่างที่เขาพลาด สิ่งที่คุณคิดว่าไม่ใช่ทางออกที่ดีกว่า?

นอกจากนี้ทราบว่าฉันกำลังพูดคุยเกี่ยวกับD 2.0ไม่D 1.0


15
ฉันแน่ใจว่าชุมชน D เห็นสิ่งนี้เพราะฉันแน่ใจว่ามี C ++ devs มากกว่า D devs แถว ๆ นี้ ด้วยวิธีนี้คุณจะได้คำตอบที่น่าสนใจมากขึ้นหรืออย่างน้อยก็หลากหลาย
Klaim

7
นอกจากนี้ D2 ยังได้รับการออกแบบโดย Walter Bright แต่กับ Alexandrescu ด้วย คุณอาจต้องการแก้ไขในคำถามของคุณ
Klaim

2
@ คำติชม: มี (และยังคงเป็น) การมีส่วนร่วมของชุมชนจำนวนมากใน D และห้องสมุดมาตรฐานด้วย
Michal Minich

28
@ ถึงเป็นภาษา C ++ ดีกว่า D ในการทำให้คุณเป็นโปรแกรมเมอร์เกลียดชีวิตของคุณ
Arlen

6
@ jokoon: จริง ๆ แล้วใช่มีงานน้อยมาก: digitalmars.com/d/2.0/interfaceToC.html
Anto

คำตอบ:


124

สิ่งที่ C ++ ส่วนใหญ่ "ทำ" ดีกว่า D คือเมตาดาต้า: C ++ มีคอมไพเลอร์ที่ดีกว่า, เครื่องมือที่ดีกว่า, ไลบรารีที่เป็นผู้ใหญ่มากขึ้น, มีการผูกมัดมากขึ้น, มีผู้เชี่ยวชาญมากขึ้น คาดหวังจากภาษาที่เป็นผู้ใหญ่มากขึ้น นี่ไม่สามารถอธิบายได้

สำหรับภาษานั้นมีบางสิ่งที่ C ++ ทำได้ดีกว่า D ในความคิดของฉัน อาจมีมากกว่านี้ แต่นี่คือบางส่วนที่ฉันสามารถแสดงรายการออกจากหัวของฉัน:

C ++ มีระบบพิมพ์ที่ดีกว่าคิดว่า
มีปัญหาเล็กน้อยกับระบบพิมพ์ใน D ในขณะนี้ซึ่งดูเหมือนจะเป็นเรื่องการกำกับดูแลในการออกแบบ ตัวอย่างเช่นในปัจจุบันมันเป็นไปไม่ได้ที่จะคัดลอก const โครงสร้างไปยังโครงสร้างที่ไม่ใช่ const ถ้า struct มีการอ้างอิงวัตถุคลาสหรือพอยน์เตอร์เนื่องจากความไวแสงของ const และวิธีที่ตัวสร้าง postblit ทำงานกับชนิดของค่า Andrei บอกว่าเขารู้วิธีแก้ปัญหานี้ แต่ไม่ได้ให้รายละเอียดใด ๆ ปัญหาสามารถแก้ไขได้อย่างแน่นอน (แนะนำตัวสร้างสำเนาสไตล์ C ++ จะเป็นการแก้ไขอย่างหนึ่ง) แต่มันเป็นปัญหาสำคัญในภาษาปัจจุบัน

ปัญหาอีกข้อหนึ่งที่บั๊กฉันคือการไม่มีกลุ่มตรรกะ (เช่นไม่mutableเหมือนใน C ++) นี่เป็นวิธีที่ดีสำหรับการเขียนโค้ดที่ปลอดภัยสำหรับเธรด แต่ทำให้ยาก (เป็นไปไม่ได้หรือไม่) ในการทำ intialisation ที่ขี้เกียจภายในวัตถุ const (คิดว่าฟังก์ชั่น const 'get' ซึ่งสร้างและแคชค่าที่ส่งคืนในการโทรครั้งแรก)

สุดท้ายให้ปัญหาที่มีอยู่เหล่านี้ผมกังวลเกี่ยวกับวิธีการส่วนที่เหลือของระบบการพิมพ์ ( pure, sharedฯลฯ ) จะโต้ตอบกับทุกสิ่งทุกอย่างในภาษาที่เมื่อพวกเขาถูกนำไปใช้ ขณะนี้ไลบรารี่มาตรฐาน (โฟบอส) ใช้ระบบพิมพ์ขั้นสูงของ D น้อยมากดังนั้นฉันคิดว่ามันสมเหตุสมผลกับคำถามว่าจะระงับความเครียดได้หรือไม่ ฉันสงสัย แต่ในแง่ดี

โปรดทราบว่า C ++ มีหูดประเภทของระบบ (เช่น const ที่ไม่ผ่านการสนับสนุนiteratorรวมถึงconst_iterator) ที่ทำให้มันค่อนข้างน่าเกลียด แต่ในขณะที่ระบบประเภทของ C ++ นั้นผิดเล็กน้อยที่ชิ้นส่วนมันไม่ทำให้คุณหยุดทำงานเช่น D บางครั้งก็ทำ

แก้ไข: เพื่อชี้แจงฉันเชื่อว่า C ++ มีระบบคิดที่ดีกว่า- ไม่จำเป็นต้องดีกว่า - ถ้ามันสมเหตุสมผล โดยพื้นฐานแล้วใน DI รู้สึกว่ามีความเสี่ยงที่เกี่ยวข้องกับการใช้ระบบพิมพ์ทุกด้านที่ไม่มีอยู่ใน C ++

บางครั้ง D ก็สะดวกไปหน่อย
คำวิจารณ์อย่างหนึ่งที่คุณมักจะได้ยินเกี่ยวกับ C ++ ก็คือมันซ่อนปัญหาระดับต่ำบางอย่างจากคุณเช่นการมอบหมายงานง่ายๆเช่นa = b;อาจจะทำอะไรหลาย ๆ อย่างเช่นการเรียกผู้ดำเนินการแปลง มองเห็นได้ยากจากรหัส บางคนเช่นนี้บางคนทำไม่ได้ ทั้งสองวิธีใน D มันจะเลวร้ายยิ่ง (ดีกว่า) เนื่องจากสิ่งที่ชอบopDispatch, @property, opApply, lazyซึ่งมีศักยภาพที่จะเปลี่ยนรหัสมองบริสุทธิ์เข้าไปในสิ่งที่คุณไม่ได้คาดหวัง

ฉันไม่คิดว่านี่เป็นปัญหาใหญ่เป็นการส่วนตัว แต่บางคนอาจพบว่าเรื่องนี้ไม่เหมาะสม

D ต้องมีการรวบรวมขยะ
ซึ่งอาจถูกมองว่าเป็นการโต้เถียงเพราะเป็นไปได้ที่จะเรียกใช้ D โดยไม่มี GC อย่างไรก็ตามเพียงเพราะเป็นไปได้ไม่ได้หมายความว่ามันใช้ได้จริง หากไม่มี GC คุณจะเสียคุณสมบัติมากมายของ D และการใช้ไลบรารี่มาตรฐานจะเหมือนกับการเดินในเขตที่วางทุ่นระเบิด (ใครจะรู้ว่าฟังก์ชั่นใดจัดสรรหน่วยความจำได้) โดยส่วนตัวแล้วฉันคิดว่ามันใช้ไม่ได้เลยหากจะใช้ D โดยไม่ใช้ GC และถ้าคุณไม่ใช่แฟนของ GCs (เหมือนฉัน) ก็อาจทำให้คุณเลิกได้

คำจำกัดความของอาร์เรย์ที่ไร้เดียงสาใน D จัดสรรหน่วยความจำ
นี่คือสัตว์เลี้ยงของฉัน:

int[3] a = [1, 2, 3]; // in D, this allocates then copies
int a[3] = {1, 2, 3}; // in C++, this doesn't allocate

เห็นได้ชัดว่าเพื่อหลีกเลี่ยงการจัดสรรใน D คุณต้องทำ:

static const int[3] staticA = [1, 2, 3]; // in data segment
int[3] a = staticA; // non-allocating copy

การจัดสรร 'หลังของคุณ' เล็กน้อยเหล่านี้เป็นตัวอย่างที่ดีของสองประเด็นก่อนหน้านี้ของฉัน

แก้ไข: โปรดทราบว่านี่เป็นปัญหาที่ทราบแล้วว่ากำลังดำเนินการอยู่
แก้ไข: ตอนนี้ได้รับการแก้ไขแล้ว ไม่มีการจัดสรรเกิดขึ้น

บทสรุป
ฉันได้เพ่งความสนใจไปที่เนกาทีฟของ D vs C ++ เพราะนั่นคือคำถามที่ถาม แต่โปรดอย่าเห็นโพสต์นี้เป็นคำสั่งที่ C ++ ดีกว่า D ฉันสามารถสร้างโพสต์ที่ใหญ่กว่าที่ D ดีกว่า กว่า C ++ ขึ้นอยู่กับคุณในการตัดสินใจเลือกใช้


ฉันดู D เมื่อสองสามปีก่อน (ก่อนหน้า 2.0) ไม่จำเป็นต้องมีการรวบรวมขยะจริงๆ - โดยค่าเริ่มต้นแล้ว แต่คุณสามารถเลือกไม่ใช้รหัสระดับต่ำได้ สิ่งที่ฉันคิดว่าผิดเกี่ยวกับสิ่งนี้คือฉันไม่สามารถหาวิธีกลับมาใช้ใหม่ได้ตัวอย่างเช่นในคอนเทนเนอร์แบบทรีรหัสไลบรารีสามารถจัดการหน่วยความจำสำหรับโหนดต้นไม้เอง ต้นไม้โดยรวมยังสามารถสะสมได้โดย IIRC เป็นตัวทำลายที่รวบรวมโหนดเหล่านั้นทั้งหมด แต่วัตถุที่อ้างอิงโดยข้อมูลในภาชนะนั้นควรจะเก็บรวบรวมด้วย - ควรมีตะขอสำหรับทำเครื่องหมายรายการข้อมูลทั้งหมดในแผนผังสำหรับ GC
Steve314

3
คุณยังคงสามารถปิดการใช้งาน GC สำหรับรหัสระดับต่ำ - ปีเตอร์กำลังบอกว่าปัจจุบันภาษาขึ้นอยู่กับมันมาก นอกจากนี้คุณยังสามารถบอก GC ในการสแกนช่วงนอกของกองการจัดการโดยใช้ API ของ: GC.addRange จาก core.memory
Vladimir Panteleev

+1 สำหรับการชี้ให้เห็นว่าไลบรารีมาตรฐาน D ถูกเก็บรวบรวมขยะและรหัส GC-off ไม่ใช่การเชื่อมต่อที่ราบรื่น ไม่ใช่สิ่งที่ฉันคิดเกี่ยวกับมัน แต่ดูเหมือนจะเป็นอุปสรรคสำคัญที่จะเอาชนะ
masonk

132

เมื่อฉันเข้าร่วมการพัฒนา D ฉันอยู่ในตำแหน่งที่แปลกประหลาดในการเป็นหนึ่งในคนที่รู้มากที่สุดเกี่ยวกับ C ++ ตอนนี้ฉันอยู่ในตำแหน่งที่แปลกประหลาดยิ่งกว่านั้นในการเป็นหนึ่งในคนที่รู้มากที่สุดเกี่ยวกับ D. ฉันไม่ได้พูดสิ่งนี้กับเครดิตที่เหมาะสมหรือสิทธิในการคุยโวมากพอ ๆ กับการพูดว่าฉันอยู่ในความอยากรู้อยากเห็น ได้เปรียบตำแหน่งเพื่อตอบคำถามนี้ เช่นเดียวกับวอลเตอร์

เมื่อถามว่า C ++ (และโดยที่ฉันหมายถึง C ++ 2011) ทำอะไรได้ดีกว่า D นั้นขัดแย้งกับตัวเองเหมือนคำถาม "ถ้าคุณจ่ายมืออาชีพทำความสะอาดบ้านของคุณสถานที่ที่พวกเขาจะออกไปคืออะไร สกปรกกว่า แต่ก่อน " อะไรก็ตามที่มีค่าคือ C ++ สามารถทำสิ่งนั้นได้ D ไม่สามารถยืนอยู่ได้เหมือนนิ้วโป้งที่เจ็บสำหรับฉันและวอลเตอร์ดังนั้นตามนิยามแล้วแทบจะไม่มีอะไรที่ C ++ สามารถทำได้ที่ไม่สามารถเข้าถึงได้

สิ่งหนึ่งที่ไม่ค่อยมีใครเข้าใจในการออกแบบภาษา (เพราะมีคนเพียงไม่กี่คนที่โชคดีที่จะทำอะไรสักอย่าง) คือมีข้อผิดพลาดที่ไม่ได้บังคับน้อยกว่าที่อาจปรากฏขึ้น ผู้ใช้ภาษาของเราหลายคนมองไปที่สิ่งก่อสร้างหรือสิ่งอื่นและพูดว่า "ใช่แล้วนี่มันผิด! ข้อเท็จจริงของเรื่องนี้ก็คือว่ากรณีที่น่าอึดอัดใจที่สุดในภาษานั้นเกิดขึ้นหลังจากการตัดสินใจขั้นพื้นฐานเพียงเล็กน้อยที่มีความสมบูรณ์และเป็นที่ต้องการ

ด้วยความคิดทั้งหมดนี้ฉันจะแจกแจงบางสิ่งที่ฉันสามารถนึกถึงได้และสำหรับแต่ละคนฉันจะอธิบายว่าตัวเลือกของ D นั้นมาจากความปรารถนาที่จะเติมเต็มในระดับสูงขึ้น

  1. D ถือว่าวัตถุทั้งหมดสามารถเคลื่อนย้ายได้โดยการคัดลอกระดับบิต สิ่งนี้ทำให้การออกแบบของ C ++ มีน้อยโดยเฉพาะที่ใช้พอยน์เตอร์ภายในเช่นคลาสที่มีพอยน์เตอร์อยู่ภายในตัวมันเอง (การออกแบบใด ๆ ดังกล่าวสามารถแปลได้โดยไม่เสียค่าใช้จ่ายหรือมีประสิทธิภาพเพียงเล็กน้อยใน D แต่จะต้องมีความพยายามในการแปลที่เกี่ยวข้อง) เราได้ทำการตัดสินใจนี้เพื่อลดความซับซ้อนของภาษาทำให้การคัดลอกวัตถุมีประสิทธิภาพมากขึ้น ปล่องก่อสร้างที่คัดลอกทั้งหมดและคุณลักษณะการอ้างอิง rvalue ทั้งหมด

  2. D ไม่อนุญาตประเภทเพศที่ไม่ชัดเจน (ที่ไม่สามารถตัดสินใจได้ว่าเป็นประเภทค่าหรือประเภทการอ้างอิง) การออกแบบดังกล่าวถูกรังเกียจอย่างเป็นเอกฉันท์ใน C ++ และเกือบจะผิดเสมอไป แต่บางชิ้นก็ถูกต้องทางเทคนิค เราเลือกตัวเลือกนี้เนื่องจากไม่อนุญาตให้ใช้รหัสที่ไม่ถูกต้องส่วนใหญ่และมีเพียงรหัสเศษส่วนเล็ก ๆ ที่สามารถออกแบบใหม่ได้ เราเชื่อว่ามันเป็นการแลกเปลี่ยนที่ดี

  3. D ไม่อนุญาตให้มีลำดับชั้นหลายรูต โปสเตอร์ก่อนหน้านี้ที่นี่ตื่นเต้นมากเกี่ยวกับหัวข้อนี้โดยเฉพาะ แต่นี่เป็นพื้นดีและไม่มีประโยชน์ที่ชัดเจนของลำดับชั้นที่ไม่มีรูทมากกว่าลำดับชั้นที่ทุกคนมีรากร่วมกัน

  4. ใน D คุณไม่สามารถโยนได้เช่น int คุณต้องโยนวัตถุที่สืบทอดได้ Throwable ไม่มีการแข่งขันที่ดีกว่าในเรื่อง D แต่สิ่งหนึ่งที่ C ++ สามารถทำได้นั้น D ไม่สามารถทำได้

  5. ใน C ++ หน่วยการห่อหุ้มเป็นคลาส ใน D เป็นโมดูล (เช่นไฟล์) วอลเตอร์ทำการตัดสินใจด้วยเหตุผลสองประการนี้คือการแมปการห่อหุ้มตามความหมายของการป้องกันระบบไฟล์และเพื่อขจัดความต้องการ "เพื่อน" ตัวเลือกนี้ผสานรวมได้ดีมากในการออกแบบแบบแยกส่วนโดยรวมของ D มันเป็นไปได้ที่จะเปลี่ยนสิ่งต่าง ๆ ให้เป็นเหมือน C ++ มากกว่า แต่มันจะบังคับสิ่งต่างๆ ตัวเลือกขอบเขตการห่อหุ้มของ C ++ นั้นดีสำหรับการออกแบบทางกายภาพของ C ++ เท่านั้น

อาจมีสิ่งเล็ก ๆ หนึ่งหรือสองอย่าง แต่โดยรวมแล้วสิ่งนี้ควรเป็น


6
@DeadMG: เพื่อให้ทำงานใน C ++ วัตถุที่ถูกย้ายจะต้องมีตัวชี้หลังไปยังวัตถุที่ชี้ไป (เพื่อให้สามารถปรับปรุงในระหว่างการสร้างสำเนา) หากเป็นเช่นนั้นใน D คุณสามารถใช้ตัวสร้าง postblit เพื่ออัปเดตตัวชี้ได้ โปรดอย่าโต้แย้งกับ D หากคุณมีความรู้ที่ผ่านไปเท่านั้น
Peter Alexander

13
@ ปีเตอร์: มันควรจะเป็นข้อมูลอ้างอิงถึงแม้ว่ามันจะเป็นช่วงอายุตลอดไปหรือไม่ ฉันควรจะเสียค่าใช้จ่ายในการจัดสรรแบบไดนามิกและทางอ้อมและแคชและค่าใช้จ่ายในการเก็บเพราะฉันต้องการที่จะนามแฝง? นอกจากนี้ฉันหวังว่านักสะสมสามารถรวบรวมได้อย่างแน่นอนสำหรับความหมายที่เทียบเท่า เห็นได้ชัดว่าไม่ได้อยู่ในการควบคุม
DeadMG

3
@sbi: การดำรงอยู่ของชนชั้นสูงไม่ส่งผลกระทบต่อทางเลือกของคุณเลย ใน lattice ประเภทคลาสจะมีด้านบนและด้านล่างเสมอ ด้านล่างมีความชัดเจนในบางภาษาเท่านั้น ด้านบน (เช่นวัตถุ ฯลฯ ) ชัดเจนในภาษาอื่น ๆ ประเภทเหล่านี้มีอยู่ในแนวคิดเสมอ; เมื่อพวกเขาสามารถเข้าถึงได้พวกเขาก็มีสิ่งอำนวยความสะดวกเพิ่มเติมให้กับผู้ใช้ภาษาโดยไม่ทำให้เกิดปัญหา
Andrei Alexandrescu

6
@quant_dev: คุณจะดีใจที่ได้ยินว่ามีโปรเจ็กต์ GSoC ในรูปร่างที่ดีซึ่งมุ่งเน้นไปที่พีชคณิตเชิงเส้นที่มีประสิทธิภาพสูงโดยใช้ BLAS นอกจากนี้ยังให้การใช้งานแบบ "ไร้เดียงสา" ของระบบดั้งเดิมที่เหมาะสมสำหรับการทดสอบและการเปรียบเทียบ เพื่อตอบคำถามที่สองของคุณ Java ตั้งค่าแถบค่อนข้างต่ำสำหรับการเปรียบเทียบไลบรารีตัวเลข มันมักจะมีปัญหาในการข้ามสิ่งกีดขวาง JNI สำหรับการเข้าถึง libs พีชคณิตประสิทธิภาพสูงและไวยากรณ์จะไม่ดีเนื่องจาก Java ขาดตัวดำเนินการมากเกินไป
Andrei Alexandrescu

4
@PeterAlexander: DeadMG อยู่ในจุดที่ถูกต้อง "คุณไม่ควรใช้พอยน์เตอร์กับค่าประเภท" ชัดเจนว่าข้อเท็จจริงที่ว่าพอยน์เตอร์ในภาษาใด ๆ มักใช้กับประเภทค่า (จริง ๆ แล้วคุณคาดหวังว่าจะเห็นการObject*ใช้อย่างกว้างขวางว่าเป็นint*)? และ D ดูเหมือนจะเพิกเฉยอย่างสมบูรณ์ โทษปรับประสิทธิภาพหรืออ้างว่าไม่มีอยู่ เห็นได้ชัดว่าผิด - แคชมิสค่อนข้างเห็นได้ชัดเจนในหลายกรณีดังนั้น C ++ จะมีความยืดหยุ่นที่เหนือกว่า D. เสมอ
Mehrdad

65

ฉันคิดว่าคุณจะมีช่วงเวลาที่ยากลำบากในการค้นหาสิ่งต่างๆใน D ซึ่งมีความหมายแย่กว่า C ++ ปัญหาส่วนใหญ่ของ D ที่คุณสามารถบอกได้ว่ามันแย่กว่านั้นคือคุณภาพของปัญหาการใช้งาน (ซึ่งโดยทั่วไปแล้วเป็นเพราะอายุน้อยกว่าภาษาและการใช้งานและได้รับการแก้ไขด้วยความเร็วที่ช้า) หรือปัญหา ไม่มีห้องสมุดของบุคคลที่สาม (ซึ่งจะมาพร้อมกับเวลา) ภาษาเองโดยทั่วไปนั้นดีกว่า C ++ และกรณีที่ภาษา C ++ เป็นภาษาที่ดีกว่าโดยทั่วไปจะเป็นที่ซึ่งมีการแลกเปลี่ยนที่ C ++ ไปทางเดียวและ D ไปอีกทางหนึ่งหรือ D ไปอีกทางหนึ่งหรือที่บางคนมีเหตุผลส่วนตัวว่าทำไม คิดว่าหนึ่งดีกว่าอีก แต่จำนวนของเหตุผลที่ตรงไปตรงมาว่าทำไมภาษา C ++ ในฐานะภาษาที่ดีกว่ามีแนวโน้มที่จะอยู่ห่างไกลกันไม่มากนัก

ในความเป็นจริงฉันต้องพินาศสมองของฉันจริงๆเพื่อหาเหตุผลว่าทำไมภาษาซีพลัสพลัสถึงดีกว่า D สิ่งที่นึกถึงโดยทั่วไปคือเรื่องของการแลกเปลี่ยน

  1. เพราะ D's constเป็นสกรรมกริยาและเพราะภาษาที่มีไม่เปลี่ยนรูปก็มีการค้ำประกันไกลดีกว่า C ++ 's constซึ่งหมายความว่า D ไม่ได้และไม่สามารถmutableมี มันไม่สามารถมีconst ตรรกะ ดังนั้นคุณจะได้รับประโยชน์มหาศาลจากระบบ const ของ D แต่ในบางสถานการณ์คุณไม่สามารถใช้งานได้constเหมือนใน C ++

  2. D มีตัวดำเนินการ cast เพียงหนึ่งตัวเท่านั้นในขณะที่C ++ มี 4 (5 ถ้าคุณนับตัวดำเนินการ cast C) สิ่งนี้ทำให้การจัดการกับการปลดเปลื้องใน D ง่ายขึ้นในกรณีทั่วไป แต่เป็นปัญหาเมื่อคุณต้องการภาวะแทรกซ้อน / ผลประโยชน์พิเศษที่const_castและพี่น้องของมันให้ แต่จริง ๆ แล้ว D มีพลังมากพอที่คุณสามารถใช้เทมเพลตเพื่อสร้าง casts ของ C ++ ดังนั้นถ้าคุณต้องการมันจริงๆคุณสามารถมีมันได้ (และพวกมันอาจจะลงเอยด้วยไลบรารีมาตรฐานของ D ในบางจุด)

  3. D มีการปลดเปลื้องโดยนัยน้อยกว่า C ++ และมีแนวโน้มมากที่จะประกาศว่าทั้งสองฟังก์ชั่นมีความขัดแย้งซึ่งกันและกัน (บังคับให้คุณต้องเจาะจงมากขึ้นเกี่ยวกับฟังก์ชันที่คุณหมายถึง - ด้วยการปลดเปลื้องหรือโดยให้เส้นทางโมดูลเต็ม ) ในบางครั้งอาจเป็นเรื่องที่น่ารำคาญ แต่ก็ป้องกันปัญหาการแย่งชิงการทำงานทุกประเภท คุณรู้ว่าคุณกำลังเรียกฟังก์ชั่นที่คุณต้องการ

  4. ระบบโมดูล D'sอยู่ไกลสะอาดกว่า #includes c ++ 's (ไม่พูดถึงวิธีที่เร็วกว่าที่รวบรวม) แต่มันขาดชนิดใด ๆ ของ namespacing เกินโมดูลตัวเอง ดังนั้นถ้าคุณต้องการเนมสเปซภายในโมดูลคุณต้องไปยังเส้นทาง Java และใช้ฟังก์ชั่นคงที่ในคลาสหรือ struct มันใช้งานได้ แต่ถ้าคุณต้องการ namespacing จริง ๆ แล้วมันไม่สะอาดเท่าการตั้งชื่อจริง อย่างไรก็ตามในสถานการณ์ส่วนใหญ่การกำหนดเนมสเปซที่โมดูลให้คุณนั้นมีมากมาย (และค่อนข้างซับซ้อนเมื่อพูดถึงเรื่องที่ขัดแย้งกันจริง ๆ )

  5. เช่น Java และ C #, D มีมรดกเดียวมากกว่ามรดกหลาย แต่ไม่เหมือน Java และ C # จะช่วยให้คุณมีวิธีที่ยอดเยี่ยมที่จะได้รับผลเช่นเดียวกันโดยไม่ต้องทั้งหมดของปัญหาที่ c ++ 's มรดกหลายมี (และ C ++' s มรดกหลายจะได้รับมากยุ่ง ในช่วงเวลาที่). ไม่เพียง แต่ D มีอินเตอร์เฟซแต่ก็มีmixins สตริง , mixins แม่แบบและนามแฝงนี้ ดังนั้นผลลัพธ์ขั้นสุดท้ายนั้นมีประสิทธิภาพมากกว่าและไม่มีปัญหาทั้งหมดที่การสืบทอดหลายอันของ C ++ ทำ

  6. คล้ายกับ C #, D แยกstructsและชั้นเรียน คลาสเป็นชนิดของการอ้างอิงที่มีการสืบทอดและมาจากObjectในขณะที่ structs เป็นชนิดของค่าที่ไม่มีการสืบทอด การแยกนี้สามารถเป็นได้ทั้งดีและไม่ดี มันกำจัดปัญหาการแบ่งแบบคลาสสิกใน C ++ และช่วยแยกประเภทซึ่งเป็นประเภทค่าจริง ๆ จากที่ควรจะเป็น polymorphic แต่อย่างน้อยในตอนแรกความแตกต่างอาจทำให้โปรแกรมเมอร์ C ++ น่ารำคาญ ท้ายที่สุดมีประโยชน์หลายประการ แต่จะบังคับให้คุณจัดการกับประเภทของคุณแตกต่างกันบ้าง

  7. ฟังก์ชั่นสมาชิกของชั้นเรียนเป็น polymorphic โดยค่าเริ่มต้น คุณไม่สามารถประกาศให้ไม่ใช่เสมือน มันขึ้นอยู่กับคอมไพเลอร์ที่จะตัดสินใจว่าพวกเขาสามารถทำได้หรือไม่ (ซึ่งจริงๆแล้วก็เป็นเพียงแค่กรณีที่พวกมันเป็นครั้งสุดท้ายและไม่ได้เอาชนะฟังก์ชั่นจากคลาสฐาน) ดังนั้นอาจเป็นปัญหาด้านประสิทธิภาพในบางกรณี อย่างไรก็ตามหากคุณไม่ต้องการความแตกต่างหลากหลายสิ่งที่คุณต้องทำก็คือใช้structและมันไม่เป็นปัญหา

  8. D มีในตัวเก็บขยะ หลายคนจาก C ++ จะพิจารณาว่าเป็นข้อเสียที่ร้ายแรงและความจริงจะได้รับการบอกในปัจจุบันการดำเนินงานของมันอาจใช้งานที่จริงจัง มันได้รับการปรับปรุง แต่ก็ยังไม่ได้เทียบกับตัวเก็บขยะของ Java อย่างแน่นอน อย่างไรก็ตามสิ่งนี้ถูกลดทอนลงด้วยสองปัจจัย หนึ่งถ้าคุณใช้structsและชนิดข้อมูลอื่น ๆเป็นหลักแล้วมันไม่ใช่ปัญหาใหญ่ หากโปรแกรมของคุณไม่ได้รับการจัดสรรและยกเลิกการจัดสรรเนื้อหาบนฮีปอย่างต่อเนื่อง และสองคุณสามารถข้ามเก็บขยะถ้าคุณต้องการและใช้เพียงซีและmalloc freeมีคุณสมบัติภาษาบางอย่าง (เช่นการแบ่งส่วนข้อมูล) ซึ่งคุณจะต้องหลีกเลี่ยงหรือระมัดระวังและบางส่วนของห้องสมุดมาตรฐานไม่สามารถใช้งานได้จริงโดยไม่ต้องใช้GCอย่างน้อย(โดยเฉพาะการประมวลผลสตริง) แต่คุณสามารถเขียนใน D โดยไม่ต้องใช้ตัวรวบรวมขยะหาก คุณต้องการจริงๆ สิ่งที่ต้องทำอย่างชาญฉลาดน่าจะใช้งานได้โดยทั่วไปแล้วหลีกเลี่ยงที่ที่การทำโปรไฟล์แสดงให้เห็นว่ามันทำให้เกิดปัญหากับโค้ดที่มีประสิทธิภาพที่สำคัญ แต่คุณสามารถหลีกเลี่ยงได้อย่างสมบูรณ์หากคุณต้องการ และคุณภาพของการดำเนินงานของGCจะดีขึ้นเมื่อเวลาผ่านไปขจัดข้อกังวลมากมายที่การใช้GCอาจทำให้เกิด ดังนั้นในที่สุดGCจะไม่เป็นปัญหาใหญ่และแตกต่างจาก Java คุณสามารถหลีกเลี่ยงได้ถ้าคุณต้องการ

อาจมีคนอื่นด้วยเช่นกัน แต่นั่นคือสิ่งที่ฉันสามารถเกิดขึ้นได้ในขณะนี้ และถ้าคุณสังเกตเห็นพวกเขากำลังแลกกันหมด D เลือกที่จะทำบางสิ่งที่แตกต่างจาก C ++ ที่มีข้อได้เปรียบที่ชัดเจนมากกว่าวิธีที่ C ++ ทำ แต่ก็มีข้อเสียเช่นกัน ซึ่งจะดีกว่าขึ้นอยู่กับสิ่งที่คุณทำและในหลาย ๆ กรณีอาจดูแย่ในตอนแรกจากนั้นคุณจะไม่มีปัญหากับมันเมื่อคุณชินกับมันแล้ว หากมีสิ่งใดปัญหาใน D โดยทั่วไปจะเป็นปัญหาใหม่ที่เกิดจากสิ่งใหม่ที่ภาษาอื่นไม่เคยทำมาก่อนหรือไม่ได้ทำในลักษณะที่ D มี โดยรวมแล้ว D เรียนรู้ได้ดีมากจากความผิดพลาดของ C ++

และ D ในฐานะที่เป็นภาษานั้นพัฒนาขึ้นกว่า C ++ ในหลาย ๆ ทางที่ฉันคิดว่าโดยทั่วไปแล้วกรณีที่ D นั้นดีกว่า

  1. D มีเงื่อนไขการรวบรวม นี่เป็นหนึ่งในคุณสมบัติที่ฉันมักพลาดเมื่อฉันเขียนโปรแกรมใน C ++ ถ้า C ++ จะเพิ่มเข้าไป C ++ จะปรับปรุงโดย leaps and bounds เมื่อพูดถึงเทมเพลต

  2. D มีเวลารวบรวมภาพสะท้อน

  3. ตัวแปรเป็นเธรดโลคัลตามค่าเริ่มต้น แต่สามารถเป็นได้sharedถ้าคุณต้องการให้เป็น นี้จะทำให้การจัดการกับหัวข้อไกลสะอาดกว่าใน C ++ คุณสามารถควบคุมได้อย่างสมบูรณ์ คุณสามารถใช้immutableและการส่งข้อความเพื่อสื่อสารระหว่างเธรดหรือคุณสามารถสร้างตัวแปรsharedและทำมันด้วยวิธี C ++ พร้อมกับตัวแปร mutexes และเงื่อนไข แม้จะได้รับการปรับปรุงให้ดีขึ้นกว่า C ++ ด้วยการแนะนำการซิงโครไนซ์ (คล้ายกับ C # และ Java) ดังนั้น D's สถานการณ์เกลียวคือไกลดีกว่า c ++ 's

  4. เทมเพลตของ Dนั้นมีประสิทธิภาพมากกว่าเทมเพลตของ C ++ ซึ่งช่วยให้คุณทำสิ่งต่างๆได้มากขึ้นและง่ายขึ้น และด้วยนอกเหนือจากข้อ จำกัด ของแม่แบบข้อความผิดพลาดที่มีวิธีที่ดีกว่าพวกเขาอยู่ใน c ++ D ทำให้แม่แบบมีประสิทธิภาพมากและใช้งานได้ ไม่มีเหตุบังเอิญที่ผู้เขียนModern C ++ Designเป็นหนึ่งในผู้ทำงานร่วมกันหลักของ D ฉันพบว่าเทมเพลต C ++ ขาดความจริงจังในการเปรียบเทียบกับเทมเพลต D และมันอาจทำให้หงุดหงิดบ่อยครั้งที่การเขียนโปรแกรมใน C ++

  5. D มีในตัวโปรแกรมสัญญา

  6. D มีกรอบการทดสอบหน่วยในตัว

  7. D มีการสนับสนุนในตัวสำหรับ unicode ด้วยstring(UTF-8), wstring(UTF-16) และdstring(UTF-32) มันทำให้ง่ายต่อการจัดการกับยูนิโค้ด และถ้าคุณต้องการใช้stringและโดยทั่วไปไม่ต้องกังวลกับยูนิโค้ดคุณสามารถทำได้ - แม้ว่าความเข้าใจพื้นฐานของยูนิโค้ดจะช่วยงานฟังก์ชันไลบรารีมาตรฐานบางอย่าง

  8. การบรรทุกเกินพิกัดของผู้ปฏิบัติงานนั้นดีกว่าของ C ++ มากทำให้คุณสามารถใช้หนึ่งฟังก์ชั่นในการโอเวอร์โหลดตัวดำเนินการหลายตัวพร้อมกันได้ ตัวอย่างที่สำคัญของเรื่องนี้คือเมื่อคุณจำเป็นต้องใช้ตัวดำเนินการทางคณิตศาสตร์ขั้นพื้นฐานมากเกินไปและการใช้งานของพวกเขาจะเหมือนกันสำหรับผู้ประกอบการ สตริงมิกซ์อินทำให้เป็นเรื่องง่ายช่วยให้คุณมีนิยามฟังก์ชั่นที่เรียบง่ายสำหรับพวกเขาทั้งหมด

  9. อาร์เรย์ของ Dนั้นดีกว่าอาร์เรย์ของ C ++ อย่างมาก ไม่เพียง แต่เป็นประเภทที่เหมาะสมที่มีความยาวเท่านั้น แต่ยังสามารถต่อท้ายและปรับขนาดได้อีกด้วย การต่อพวกมันเป็นเรื่องง่าย และที่สำคัญที่สุดพวกเขามีการแบ่งส่วน และนั่นเป็นประโยชน์อย่างมากสำหรับการประมวลผลอาร์เรย์ที่มีประสิทธิภาพ สตริงเป็นอาร์เรย์ของตัวละครใน D และไม่ใช่ปัญหา (อันที่จริงมันยอดเยี่ยมมาก!) เพราะอาร์เรย์ของ D นั้นมีประสิทธิภาพมาก

ฉันสามารถไปเรื่อย ๆ การปรับปรุงจำนวนมากที่ D ให้นั้นเป็นสิ่งเล็ก ๆ น้อย ๆ (เช่นใช้thisสำหรับชื่อคอนสตรัคเตอร์หรือไม่อนุญาตหากคำสั่งหรือเนื้อความลูปที่เซมิโคลอนเป็นทั้งตัว) แต่บางตัวก็มีขนาดใหญ่พอสมควรและเมื่อคุณรวมมันเข้าด้วยกัน ทำให้ประสบการณ์การเขียนโปรแกรมดีขึ้นมาก C ++ 0x เพิ่มคุณสมบัติบางอย่างที่ D มีซึ่ง C ++ หายไป (เช่นautoและ lambdas) แต่ถึงแม้จะมีการปรับปรุงทั้งหมด แต่ก็ยังคงมีไม่มากซึ่ง C + + เป็นภาษาที่ดีกว่า D

ไม่มีคำถามว่ามีเหตุผลส่วนตัวมากมายที่จะทำให้เหมือนกันและความไม่บรรลุนิติภาวะของการดำเนินงานของ D อาจเป็นปัญหาได้ตลอดเวลา (แม้ว่ามันจะได้รับการปรับปรุงอย่างรวดเร็วในช่วงปลาย - โดยเฉพาะอย่างยิ่งเมื่อย้ายที่เก็บไปยังGitHub ) และการขาดห้องสมุดบุคคลที่สามอาจเป็นปัญหาได้อย่างแน่นอน (แม้ว่าข้อเท็จจริงที่ว่า D สามารถเรียกใช้ฟังก์ชั่น Cได้อย่างง่ายดาย- และในระดับที่น้อยกว่านั้นฟังก์ชั่น C ++ - ช่วยลดปัญหาได้อย่างแน่นอน) แต่สิ่งเหล่านี้คือคุณภาพของปัญหาการใช้งานมากกว่าปัญหาเกี่ยวกับภาษานั้น ๆ และเมื่อคุณภาพของปัญหาการใช้งานได้รับการแก้ไขแล้วมันจะกลายเป็นเรื่องที่น่าพึงพอใจที่จะใช้ D.

ดังนั้นฉันคิดว่าคำตอบสั้น ๆ สำหรับคำถามนี้คือ "น้อยมาก" D โดยทั่วไปแล้วภาษาดีกว่าภาษาซีพลัสพลัส


2
ภาษาในการรวบรวมขยะใช้หน่วยความจำมากกว่า 2-5x มากกว่า GC lang ที่ไม่ใช่ (ตามการพูดคุยของ Alexandrescu บน YT) ซึ่งเป็นปัญหาแน่นอนหากการใช้หน่วยความจำนั้นเป็นปัญหาคอขวด
NoSenseEtAl

9

RAII และการใช้หน่วยความจำสแต็ก

D 2.0 ไม่อนุญาตให้ RAII เกิดขึ้นบนสแต็กเพราะจะลบค่าของscopeคำหลักในการจัดสรรอินสแตนซ์ของคลาสบนสแต็ก

คุณไม่สามารถสืบทอดค่าชนิดใน D ดังนั้นมีประสิทธิภาพที่บังคับให้คุณทำการจัดสรรฮีปสำหรับ RAII ทุกรูปแบบ
นั่นคือเว้นแต่คุณจะใช้emplaceแต่มันเจ็บปวดมากที่จะใช้เนื่องจากคุณต้องจัดสรรหน่วยความจำด้วยมือ (ฉันยังไม่พบว่าใช้งานได้จริงemplaceใน D. )


6

C ++ ดีกว่าที่จะบังคับให้คุณพูดอย่างละเอียด สิ่งนี้อาจจะดีขึ้นหรือแย่ลงในดวงตาของคุณขึ้นอยู่กับว่าคุณชอบอนุมานหรือการใช้คำฟุ่มเฟือย

เปรียบเทียบการบันทึกเวลาใช้งานใน C ++ :

template <typename ReturnType, typename... Args>
function<ReturnType (Args...)> memoize(function<ReturnType (Args...)> func)
{
    map<tuple<Args...>, ReturnType> cache;
    return ([=](Args... args) mutable {
            tuple<Args...> t(args...);
            return cache.find(t) == cache.end()
                ? cache[t] : cache[t] = func(args...);
    });
}

ด้วยสิ่งเดียวกันใน D:

auto memoize(F)(F func)
{
    alias ParameterTypeTuple!F Args;
    ReturnType!F[Tuple!Args] cache;
    return (Args args)
    {
        auto key = tuple(args);
        return key in cache ? cache[key] : (cache[key] = func(args));
    };
}

แจ้งให้ทราบล่วงหน้าเช่นฟุ่มเฟื่อยพิเศษกับtemplate <typename ReturnType, typename... Args>เมื่อเทียบกับ(F), Args...กับArgs, args...เมื่อเทียบกับargsฯลฯ
สำหรับดีขึ้นหรือแย่ลง, C ++ เป็นอย่างละเอียดมากขึ้น

แน่นอนคุณสามารถทำได้ใน D:

template memoize(Return, Args...)
{
    Return delegate(Args) memoize(Return delegate(Args) func)
    {
        Return[Tuple!Args] cache;
        return delegate(Args args)
        {
            auto key = tuple(args);
            return key in cache ? cache[key] : (cache[key] = func(args));
        };
    }
}

และพวกมันจะมีลักษณะเกือบเหมือนกัน แต่เมื่อถึงตอนนี้จะต้องมีdelegateกในขณะที่ต้นฉบับยอมรับวัตถุใด ๆ ที่เรียกได้ (รุ่น C ++ 0x ต้องใช้std::functionวัตถุดังนั้นไม่ว่าจะด้วยวิธีใดก็ตามจะยิ่งละเอียดและเข้มงวดมากขึ้นในอินพุตของ ... ซึ่งอาจดีถ้าคุณชอบการใช้คำฟุ่มเฟื่อยไม่ดีถ้าคุณไม่ได้)


2

ฉันไม่ค่อยรู้อะไรเกี่ยวกับ D แต่มีโปรแกรมเมอร์ C ++ หลายคนที่ฉันไม่ชอบอย่างมากและฉันต้องเห็นด้วย - ฉันไม่ชอบหน้าตาของ D และจะไม่เข้าใกล้

เพื่อที่จะเข้าใจว่าทำไม D ไม่ได้รับแรงฉุดมากขึ้นคุณต้องเริ่มด้วยการทำความเข้าใจกับสิ่งที่ดึงดูดผู้คนสู่ C ++ ในคำเดียวเหตุผลจำนวนหนึ่งคือการควบคุม เมื่อคุณโปรแกรมใน C ++ คุณจะสามารถควบคุมโปรแกรมของคุณได้อย่างสมบูรณ์ ต้องการแทนที่ไลบรารีมาตรฐานหรือไม่ คุณสามารถ. ต้องการที่จะทำตัวชี้ที่ไม่ปลอดภัยปลดเปลื้อง? คุณสามารถ. ต้องการที่จะละเมิดความถูกต้อง const? คุณสามารถ. ต้องการแทนที่ตัวจัดสรรหน่วยความจำหรือไม่ คุณสามารถ. ต้องการคัดลอกรอบ ๆ หน่วยความจำโดยไม่คำนึงถึงประเภทของมันหรือไม่ ถ้าคุณต้องการจริงๆ ต้องการรับช่วงจากการใช้งานหลายครั้งหรือไม่ มันเป็นงานศพของคุณ เฮ้คุณยังสามารถรับไลบรารี่คอลเลคชั่นได้เช่นตัวสะสม Boehm จากนั้นคุณมีปัญหาเช่นประสิทธิภาพซึ่งติดตามการควบคุมอย่างใกล้ชิดยิ่งมีโปรแกรมเมอร์มากเท่าไรเขาก็ยิ่งสามารถสร้างโปรแกรมที่เหมาะสมได้มากขึ้นเท่านั้น

นี่คือบางสิ่งที่ฉันเห็นเมื่อทำวิจัยเล็กน้อยและพูดคุยกับผู้คนสองสามคนที่ได้ลอง:

ลำดับชั้นของประเภทแบบรวม ผู้ใช้ C ++ ใช้การสืบทอดค่อนข้างน้อยนักเขียนโปรแกรม C ++ ส่วนใหญ่ชอบการแต่งเพลงและประเภทควรเชื่อมโยงผ่านการสืบทอดหากมีเหตุผลที่ดีในการทำเช่นนั้น แนวคิดของ Object ละเมิดหลักการนี้อย่างยิ่งโดยเชื่อมโยงทุกประเภท นอกจากนี้ยังเป็นการละเมิดหนึ่งในหลักการพื้นฐานที่สุดของ C ++ นั่นคือคุณใช้สิ่งที่คุณต้องการเท่านั้น ไม่ได้รับเลือกเกี่ยวกับการสืบทอดจาก Object และค่าใช้จ่ายที่สอดคล้องกับมันนั้นมีความสำคัญอย่างยิ่งต่อสิ่งที่ C ++ หมายถึงเป็นภาษาในแง่ของการให้โปรแกรมเมอร์สามารถควบคุมโปรแกรมของเขาได้

ฉันเคยได้ยินปัญหาเกี่ยวกับฟังก์ชั่นและผู้ได้รับมอบหมาย เห็นได้ชัดว่า D มีทั้งฟังก์ชั่นและผู้รับมอบสิทธิ์เป็นประเภทฟังก์ชั่น callable เวลาทำงานและพวกเขาจะไม่เหมือนกัน แต่พวกเขาจะเปลี่ยนได้หรือ ... บางสิ่งบางอย่าง? เพื่อนของฉันมีปัญหาเล็กน้อยกับพวกเขา นี่คือการลดระดับจาก C ++ ซึ่งเพิ่งมีstd::functionและคุณเสร็จสิ้นแล้ว

จากนั้นคุณก็มีความเข้ากันได้ D เข้ากันไม่ได้กับ C ++ โดยเฉพาะ ฉันหมายความว่าไม่มีภาษาที่เข้ากันได้กับ C ++ ลองเผชิญหน้ากับมันยกเว้น C ++ / CLI ที่เป็นการโกง แต่เป็นอุปสรรคต่อการเข้า

จากนั้นมีบางสิ่งอื่น ๆ ตัวอย่างเช่นเพียงอ่านรายการ Wikipedia

import std.metastrings;
pragma(msg, Format!("7! = %s", fact_7));
pragma(msg, Format!("9! = %s", fact_9));

printfเป็นหนึ่งในฟังก์ชั่นที่ไม่ปลอดภัยที่สุดที่เคยคิดในครอบครัวเดียวกันกับปัญหาใหญ่ ๆ เช่นgetsจากไลบรารีมาตรฐาน C มาตรฐานเก่า หากคุณค้นหาใน Stack Overflow คุณจะพบคำถามมากมายเกี่ยวกับการใช้ผิดประเภท พื้นฐานprintfเป็นการละเมิดDRY- คุณให้ประเภทในสตริงรูปแบบจากนั้นให้อีกครั้งเมื่อคุณให้อาร์กิวเมนต์ มีการละเมิด DRY เมื่อคุณทำผิดสิ่งเลวร้ายจะเกิดขึ้นถ้าคุณเปลี่ยน typedef จากจำนวนเต็ม 16 บิตเป็น 32 บิต นอกจากนี้ยังขยายไม่ได้เลยลองจินตนาการว่าจะเกิดอะไรขึ้นถ้าทุกคนคิดค้นตัวระบุรูปแบบของตนเอง iostreams ของ C ++ อาจช้าและตัวเลือกของผู้ให้บริการอาจไม่ได้ยอดเยี่ยมที่สุดและส่วนต่อประสานของพวกเขาสามารถใช้งานได้ แต่รับประกันว่าปลอดภัยและไม่ละเมิด DRY และสามารถขยายได้อย่างง่ายดาย นี่ไม่ใช่สิ่งที่สามารถพูดprintfได้

ไม่มีการสืบทอดหลายรายการ นั่นไม่ใช่วิธี C ++ โปรแกรมเมอร์ C ++ คาดหวังว่าจะสามารถควบคุมโปรแกรมได้อย่างสมบูรณ์และภาษาที่บังคับใช้ในสิ่งที่คุณไม่สามารถสืบทอดมาได้นั้นเป็นการละเมิดหลักการดังกล่าว นอกจากนี้ยังทำให้การรับมรดก (ยิ่งกว่านั้น) เปราะบางเพราะถ้าคุณเปลี่ยนชนิดจากอินเทอร์เฟซเป็นคลาสเพราะคุณต้องการให้มีการนำไปใช้งานเริ่มต้นหรือบางสิ่งบางอย่างรหัสผู้ใช้ทั้งหมดของคุณก็พัง นั่นไม่ใช่สิ่งที่ดี

อีกตัวอย่างหนึ่งคือและstring wstringใน C ++ มันค่อนข้างเจ็บปวดที่ต้องแปลงระหว่างกันและไลบรารีนี้สนับสนุน Unicode และไลบรารี C เก่านี้ใช้เพียงอย่างเดียวconst char*และต้องเขียนฟังก์ชันเดียวกันรุ่นต่าง ๆ ขึ้นอยู่กับชนิดอาร์กิวเมนต์ของสตริงที่คุณต้องการ ตัวอย่างเช่นส่วนหัวของ Windows มีมาโครที่น่ารำคาญอย่างมากที่จะรับมือกับปัญหาที่มักจะรบกวนการทำงานของรหัสของคุณ การเพิ่มdstringการมิกซ์นั้นจะทำให้สิ่งเลวร้ายลงเท่านั้นตอนนี้แทนที่จะต้องมีสตริงสองประเภทคุณต้องจัดการสามอย่าง การมีสตริงประเภทมากกว่าหนึ่งประเภทจะช่วยเพิ่มความเจ็บปวดในการบำรุงรักษาและแนะนำรหัสที่ซ้ำ ๆ เกี่ยวกับสตริง

Scott Meyers เขียน:

D เป็นภาษาการเขียนโปรแกรมที่สร้างขึ้นเพื่อช่วยโปรแกรมเมอร์ในการรับมือกับความท้าทายของการพัฒนาซอฟต์แวร์ที่ทันสมัย มันทำเช่นนั้นด้วยการสนับสนุนโมดูลที่เชื่อมต่อถึงกันผ่านอินเทอร์เฟซที่แม่นยำการรวมกันของกระบวนทัศน์การเขียนโปรแกรมแบบบูรณาการอย่างแน่นหนาการแยกเธรดที่บังคับใช้ภาษาความปลอดภัยประเภทโมดูลาร์

การแยกเธรดที่บังคับใช้ภาษาไม่ได้เป็นข้อดี โปรแกรมเมอร์ C ++ คาดหวังว่าจะสามารถควบคุมโปรแกรมได้อย่างเต็มที่และภาษาที่ใช้บังคับบางสิ่งนั้นไม่ใช่สิ่งที่แพทย์สั่ง

ฉันยังจะพูดถึงการจัดการสตริงเวลารวบรวม D มีความสามารถในการตีความรหัส D ในเวลารวบรวม นี่ไม่ใช่ข้อดี พิจารณาอาการปวดหัวครั้งใหญ่ที่เกิดจากตัวประมวลผลล่วงหน้าที่ค่อนข้าง จำกัด ของ C ซึ่งเป็นที่รู้จักกันดีโดยโปรแกรมเมอร์ C ++ ทุกคนที่มีประสบการณ์ ความสามารถในการสร้างรหัส D ในเวลารวบรวมนั้นยอดเยี่ยม แต่ควรมีความหมายไม่ใช่วากยสัมพันธ์

นอกจากนี้คุณสามารถคาดหวังการสะท้อนบางอย่าง D มีการรวบรวมขยะซึ่งโปรแกรมเมอร์ C ++ จะเชื่อมโยงกับภาษาเช่น Java และ C # ซึ่งตรงกันข้ามกับปรัชญาในเชิงปรัชญาโดยตรงและความคล้ายคลึงกันทางไวยากรณ์จะทำให้พวกเขานึกถึงเช่นกัน สิ่งนี้ไม่จำเป็นต้องมีเหตุผลอย่างสมเหตุสมผล แต่เป็นสิ่งที่ควรสังเกตอย่างแน่นอน

โดยพื้นฐานแล้วมันไม่ได้ให้สิ่งที่โปรแกรมเมอร์ C ++ ไม่สามารถทำได้ อาจจะง่ายกว่าในการเขียน metaprogram แบบ factorial ใน D แต่เราสามารถเขียน metaprogram แบบ factorial ใน C ++ ได้ บางทีใน D คุณสามารถเขียน ray-tracer แบบ compile-time ได้ แต่ไม่มีใครต้องการทำเช่นนั้น เปรียบเทียบกับการละเมิดพื้นฐานของปรัชญา C ++ สิ่งที่คุณสามารถทำได้ใน D นั้นไม่น่าสังเกตเป็นพิเศษ

แม้ว่าสิ่งเหล่านี้เป็นปัญหาบนพื้นผิวเท่านั้นฉันก็ค่อนข้างแน่ใจว่าความจริงที่ว่าบนพื้นผิว D จริงๆแล้วไม่ดูเหมือน C ++ เลยน่าจะเป็นเหตุผลที่ดีที่โปรแกรมเมอร์ C ++ หลายคนไม่ย้ายไปที่ D บางที D ต้องทำงานโฆษณาให้ดีขึ้นด้วยตัวเอง


9
@DeadMG: มันไม่ถูกต้อง 100% และไม่มีจุดที่จะพูดนี่คือการลดระดับจาก C ++ ซึ่งเพิ่งมีstd::functionและคุณทำเสร็จแล้ว ทำไม? ตัวอย่างเช่นคุณยังมีพอยน์เตอร์ของฟังก์ชัน มันตรงกับสิ่งเดียวกันใน D: D's "ฟังก์ชั่น" เป็นตัวชี้ฟังก์ชั่นและ D's "ผู้แทน" เป็นเช่นเดียวกับ C ++ 's std::function(ยกเว้นว่าพวกเขากำลังในตัว) ไม่มี "ลดระดับ" ไม่ว่าที่ใด - และมีการโต้ตอบระหว่างกันแบบ 1: 1 ดังนั้นจึงไม่ควรสับสนหากคุณคุ้นเคยกับ C ++
Mehrdad

10
@ Mark Trapp: ฉันต้องยอมรับว่าฉันไม่ค่อยเข้าใจจุดยืนของคุณในหัวข้อนี้ - คุณไม่ควรใช้ความเห็นเพื่อแสดงความคิดเห็นในคำตอบ?
klickverbot

6
@ Mark Trapp: ประเด็นของฉันคือความคิดเห็นส่วนใหญ่ที่นี่ไม่ล้าสมัย (การสนทนาเมตาที่คุณเชื่อมโยงนั้นใช้เฉพาะกับข้อเสนอแนะที่ได้รับการรวมไว้ในโพสต์ต้นฉบับ) แต่ชี้ให้เห็นความไม่ถูกต้องจริงในโพสต์ .
klickverbot

7
หมายเหตุเกี่ยวกับรูปแบบ: ฟังก์ชั่นการจัดรูปแบบของ D คือประเภทที่ปลอดภัย (แก้ปัญหาความปลอดภัย / ล้น) และไม่ละเมิด DRY เนื่องจากสตริงรูปแบบจะระบุว่าอาร์กิวเมนต์ควรจัดรูปแบบอย่างไรไม่ใช่ประเภท นี่เป็นไปได้ที่ต้องขอบคุณ variadics ของ typesafe D ดังนั้นการคัดค้านอย่างน้อยนั้นจึงไม่ถูกต้องสมบูรณ์
Justin W

17
@ Mark: สิ่งที่เป็นนโยบายในปัจจุบันเกี่ยวกับพวกเขาฉันคิดว่ามันโง่และขัดขวางว่าการอภิปรายแสดงความคิดเห็นจะถูกลบออก ฉันคิดว่าคำตอบนี้มีการอภิปรายอย่างกว้างขวาง (ซึ่งตอนนี้ฉันสนใจ) แต่ฉันไม่แน่ใจและฉันไม่มีทางรู้ ห้องนั้นคุณเชื่อมโยงกับข้อความกว่า 10k และฉันไม่มีโอกาสเลยที่จะพบการสนทนาที่ฉันจำได้ว่าเกิดขึ้น แต่ไม่สามารถจำเนื้อหาได้ การสนทนาเกี่ยวกับคำตอบนี้อยู่ที่นี่สำหรับคำตอบนี้และไม่ใช่ไปที่ห้องแชทบางห้องซึ่งอาจรวมอยู่ในการสนทนาเรื่องเพศยาเสพติดและ rock'n'roll
sbi

1

สิ่งหนึ่งที่ผมชื่นชมใน C ++ คือความสามารถในการจัดทำเอกสารอาร์กิวเมนต์ฟังก์ชันหรือค่าตอบแทนเป็น c ++ อ้างอิงแทนตัวชี้จึงหมายความการที่ไม่nullคุ้มค่า

รุ่น D:

class A { int i; }

int foo(A a) {
    return a.i; // Will crash if a is null
}

int main() {
    A bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    return foo(bar);
}

รุ่น C ++:

class A { int i; };

int foo(A& a) {
    return a.i; // Will probably not crash since
                // C++ references are less likely
                // to be null.
}

int main() {
    A* bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    // Hm.. I have to dereference the bar-pointer
    // here, otherwise it wont compile.  Lets add
    // a check for null before.
    if (bar)
        return foo(*bar);
    return 0;
}

เพื่อความเป็นธรรมคุณสามารถเข้าใกล้ C ++ มากโดยการทำเครื่องหมายAD structและทำเครื่องหมายfoo()-argument เป็น a ref(คลาสเป็นประเภทอ้างอิงและ structs เป็นประเภทค่าใน D คล้ายกับ C #)

ฉันเชื่อว่ามีแผนที่จะสร้างNonNullableเทมเพลตสำหรับคลาสเป็นโครงสร้างไลบรารีมาตรฐาน D แทน แม้กระนั้นฉันก็ชอบความกะทัดรัดของการType&เปรียบเทียบNonNullable(Type)และจะชอบไม่เป็นโมฆะเป็นค่าเริ่มต้น (การแสดงผลสิ่งที่ชอบTypeและNullable(Type)) แต่มันสายเกินไปที่จะเปลี่ยนแปลงสิ่งนั้นสำหรับ D และฉันกำลังจะปิดหัวข้อในขณะนี้


3
ทั้งฟังก์ชั่นการขัดแย้งและค่าตอบแทน D สามารถทำเครื่องหมายด้วยrefที่จะให้ผลเช่นเดียวกับ C ++ &'s แตกต่างที่สำคัญหนึ่งคือการที่จะไม่ใช้ชั่วคราวแม้ว่าจะเป็นref const
Jonathan M Davis

ฉันชอบวิธีที่ไม่อนุญาตให้มีการอ้างอิงถึงตัวแปรท้องถิ่นใน D ฉันไม่ทราบว่าจนกว่าฉันจะอ่านความคิดเห็นของคุณ แต่คุณยังสามารถส่งคืนการอ้างอิงโมฆะที่ไม่ใช่ในท้องที่ได้โดยไม่ต้องนึกถึงมันในวิธีที่ผู้ควบคุมการอ้างอิงจะทำให้คุณคิด
lumor

คุณกำลังสับสนในสิ่งต่าง ๆ คลาสมักจะมีการอ้างอิงและแยกจากการอ้างอิง การอ้างอิงใน D เป็นเหมือนการอ้างอิงใน Java พวกเขากำลังจัดการพอยน์เตอร์ การผ่านหรือการคืนโดยการอ้างอิงนั้นเหมือนกับการส่งหรือกลับด้วย & ใน C ++ ผ่านการอ้างอิงระดับโดยอ้างอิงก็เหมือนผ่านตัวชี้ใน C ++ กับ & (เช่น A * &) คลาสไม่ได้อยู่ในสแต็ก ใช่ NonNullable จะทำให้มีการอ้างอิงระดับซึ่งรับประกันว่าจะไม่เป็นโมฆะ แต่แยกจากอ้างอิงอย่างสมบูรณ์ สิ่งที่คุณพยายามทำในรหัส C ++ ไม่ทำงานใน D เนื่องจากคลาสไม่ทำงานบนสแต็ก โครงสร้างทำ
Jonathan M Davis

1
ใช่แล้วความสามารถในการอ้างอิงคลาสซึ่งไม่ใช่ nullabe น่าจะดี แต่ C ++ สามารถทำสิ่งที่คุณแสดงได้เพราะอนุญาตให้คลาสอยู่บนสแต็กและอนุญาตให้ยกเลิกการชี้ตัวชี้ และในขณะที่คุณสามารถยกเลิกการลงทะเบียนพอยน์เตอร์ใน D คลาสจะเป็นการอ้างอิงไม่ใช่พอยน์เตอร์ดังนั้นคุณจะไม่สามารถยกเลิกการลงทะเบียนได้ เนื่องจากคุณไม่สามารถวางมันลงบนสแต็กและคุณไม่สามารถตรวจสอบพวกมันได้จึงไม่มีวิธีที่สร้างไว้ใน D เพื่อให้มีคลาสที่ไม่สามารถเป็นโมฆะได้ มันคือการสูญเสีย แต่ NonNullable จะแก้ไขและผลกำไรจากการแยก structs และคลาสมักจะยิ่งใหญ่กว่าอยู่ดี
Jonathan M Davis

2
การอ้างอิง C ++ ต้องไม่เป็นโมฆะตามมาตรฐานภาษา (การพูดว่า "อาจจะไม่เป็นโมฆะ" ไม่ถูกต้องเนื่องจากไม่สามารถเป็นโมฆะ) ฉันหวังว่าจะมีวิธีการที่ไม่อนุญาตให้เป็นค่าว่างสำหรับคลาส
jsternberg

1

สิ่งที่สำคัญที่สุดที่ C ++ "ทำได้ดีกว่า" คือ D กำลังเชื่อมต่อกับไลบรารี่ดั้งเดิม เอนจิ้นสามมิติแบบ OpenCL และอื่น ๆ เนื่องจาก D เป็นสิ่งใหม่จึงมีไลบรารีที่แตกต่างกันจำนวนน้อยกว่าให้เลือก

ข้อแตกต่างที่สำคัญอีกประการหนึ่งระหว่าง C ++ และ D คือC ++ มีผู้ขายอิสระทางการเงินหลายราย แต่ในปี 2014 D มีเพียงคนเดียวเท่านั้นทีม 2 คนที่สร้างมันขึ้นมา เป็นที่น่าสนใจว่า"หลักการแหล่งที่มาที่สอง"ที่บอกว่าโครงการไม่ควรขึ้นอยู่กับเทคโนโลยีส่วนประกอบที่มีเพียงหนึ่งเดียวผู้ขายดูเหมือนว่าจะเก็บไว้แม้กระทั่งสำหรับซอฟต์แวร์

สำหรับการเปรียบเทียบล่าม Ruby รุ่นแรกถูกเขียนขึ้นโดยนักประดิษฐ์ของ Ruby ผู้ Yukihiro Matsumoto แต่ล่าม Ruby ที่สำคัญในยุค 2014 นั้นถูกเขียนขึ้นโดยคนอื่น ดังนั้น Ruby จึงถูกมองว่าเป็นภาษาที่มีผู้จำหน่ายอิสระมากกว่าหนึ่งราย D อาจเป็นเทคโนโลยีที่ยอดเยี่ยม แต่ขึ้นอยู่กับนักพัฒนาไม่กี่คนที่พัฒนามัน

ประวัติความเป็นมาของ Java แสดงให้เห็นว่าแม้ว่าเทคโนโลยีในกรณีนี้ Java มีความละเอียด แต่ทางการเงิน แต่ก็มีความเสี่ยงสูงที่เทคโนโลยีจะถูกทิ้งโดยไม่คำนึงถึงฐานผู้ใช้องค์กรขนาดใหญ่ การอ้างอิงของApache Software Foundationที่ EC ย่อมาจาก "คณะกรรมการบริหาร":

ออราเคิลจัดหาข้อกำหนดและใบอนุญาตข้อกำหนด Java SE 7 ให้แก่ EC ซึ่งขัดแย้งกับตนเอง จำกัด การกระจายการใช้งานข้อมูลจำเพาะอย่างรุนแรงและที่สำคัญที่สุดห้ามมิให้มีการแจกจ่ายการใช้งานโอเพ่นซอร์สอิสระของข้อมูลจำเพาะ

จากบันทึกทางประวัติศาสตร์อาจกล่าวได้ว่า Java applets มีฮาร์ดแวร์เร่งความเร็วผ้าใบ 3 มิติก่อน HTML5 WebGL ได้รับการพัฒนา ปัญหาความเร็วเริ่มต้นของแอปเพล็ต Java อาจได้รับการแก้ไขหาก Java เป็นโครงการชุมชน แต่ผู้บริหารของนักการเงินคนเดียวของ Java คือ Sun Microsystems ไม่พบว่ามีความสำคัญพอที่จะทำให้การใช้งาน Java ได้รับการแก้ไข ผลลัพธ์สุดท้าย: ผืนผ้าใบ HTML5 โดยผู้ค้าหลายรายในฐานะ "แบบจำลองของคนจน" ของเฟรมเวิร์ก Java GUI (การแกว่ง ฯลฯ ) ที่น่าสนใจมากพอที่ฝั่งเซิร์ฟเวอร์ภาษาการเขียนโปรแกรม Python มีข้อได้เปรียบเดียวกับที่ Java สัญญาไว้: เขียนหนึ่งครั้งทำงานบนเซิร์ฟเวอร์ทุกเครื่องโดยไม่คำนึงถึงฮาร์ดแวร์ Python เป็นเรื่องเกี่ยวกับอายุ / อายุน้อยกว่าเป็น Java แต่แตกต่างจาก Java มัน '

สรุป:

เมื่อประเมินเทคโนโลยีเพื่อใช้ในการผลิตคุณสมบัติที่สำคัญที่สุดของเทคโนโลยีคือคนที่พัฒนามันกระบวนการทางสังคมที่มีการพัฒนาเกิดขึ้นและจำนวนทีมพัฒนาอิสระทางการเงิน

ไม่ว่าจะเป็นประโยชน์มากกว่าที่จะใช้เทคโนโลยี T1 มากกว่าเทคโนโลยี T2 ขึ้นอยู่กับผู้ขายของเทคโนโลยีและเทคโนโลยี T1 ช่วยให้การแก้ปัญหาที่เกี่ยวข้องกับโครงการถูกกว่า T2 หรือไม่ ตัวอย่างเช่นหากปัญหาของผู้จัดหารายเดียวถูกละเว้นดังนั้นสำหรับระบบข้อมูล Java จะเป็นเทคโนโลยี "ดีกว่า" กว่า C ++ เนื่องจากไบนารี Java ไม่จำเป็นต้องคอมไพล์ใหม่ในการปรับใช้กับฮาร์ดแวร์ใหม่และจำนวนของการพัฒนาซอฟต์แวร์ที่เกี่ยวข้องกับการจัดการหน่วยความจำ เล็กกว่าสำหรับ Java มากกว่าสำหรับ C ++ โครงการที่พัฒนาตั้งแต่เริ่มต้นเช่นโครงการที่ไม่ขึ้นอยู่กับห้องสมุดอื่น ๆ อาจมีราคาถูกกว่าที่จะพัฒนาใน D มากกว่า C ++ แต่ในทางกลับกัน C ++ มีผู้ขายมากกว่าหนึ่งรายและมีความเสี่ยงน้อยกว่าในระยะยาว . (ตัวอย่าง Java ซึ่ง Sun Microsystems เกือบจะตกลง

วิธีแก้ปัญหาที่เป็นไปได้สำหรับข้อ จำกัด C ++ บางรายการ

หนึ่งในวิธีแก้ไขปัญหาที่เป็นไปได้สำหรับข้อ จำกัด บางประการของ C ++ คือการใช้รูปแบบการออกแบบโดยที่งานเริ่มต้นถูกนำไปเป็นชิ้น ๆ และชิ้นส่วนต่าง ๆ ถูกเรียงลำดับ (จำแนก, จัดกลุ่ม, แบ่ง, อื่น ๆ สิ่งเดียวกัน) ถึง 2 คลาส: ควบคุมงานที่เกี่ยวข้องกับตรรกะที่รูปแบบการเข้าถึงหน่วยความจำไม่อนุญาตให้มีตำแหน่ง งานที่คล้ายกับการประมวลผลสัญญาณซึ่งทำได้ง่าย ๆ การประมวลผลงาน "ชอบ" สามารถนำมาใช้เป็นชุดของโปรแกรมคอนโซลที่ค่อนข้างง่าย ตรรกะการควบคุมที่เกี่ยวข้องกับงานจะถูกวางไว้ในสคริปต์เดียวที่เขียนใน Ruby หรือ Python หรืออย่างอื่นที่การพัฒนาซอฟต์แวร์มีความสำคัญมากกว่าความเร็ว

เพื่อหลีกเลี่ยงการเริ่มต้นกระบวนการระบบปฏิบัติการที่มีราคาแพงและการคัดลอกข้อมูลระหว่างกระบวนการของระบบปฏิบัติการชุดของแอปพลิเคชันคอนโซล C ++ ขนาดเล็กอาจถูกนำมาใช้เป็นโปรแกรม C ++ เดี่ยวที่ถูกบูทเป็น "servlet" โดย Ruby / Python / etc ต้นฉบับ Ruby / Python / etc สคริปต์ปิดการทำงานเซิร์ฟเล็ตก่อนออก การสื่อสารระหว่าง "servlet" และ Ruby / Python / etc สคริปต์เกิดขึ้นบน Linux ชื่อไพพ์หรือกลไกที่คล้ายกัน

หากงานเริ่มต้นไม่ได้ยืมตัวเองให้แบ่งออกเป็นส่วน ๆ ที่สามารถจำแนกได้เป็น 2 คลาสดังกล่าวแล้วสิ่งที่ต้องลองอาจเป็นวลีปัญหาใหม่เพื่อให้งานเริ่มต้นเปลี่ยนไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.