Một số tính năng ngôn ngữ, ngay cả khi chúng là bổ sung, có thể thay đổi toàn bộ cách ngôn ngữ thực tế cần được sử dụng. Như một ví dụ xem xét trường hợp này:
lock_mutex(&mutex);
// call some functions
...
unlock_mutex(&mutex);
Nếu đoạn mã trên liên quan đến các chức năng gọi được triển khai trong C ++, chúng ta có thể gặp rắc rối, vì bất kỳ một trong số các cuộc gọi chức năng đó có thể ném và chúng ta sẽ không bao giờ mở khóa mutex trong những đường dẫn đặc biệt đó.
Công cụ phá hủy không còn nằm trong địa hạt tiện lợi để giúp các lập trình viên tránh quên giải phóng / giải phóng tài nguyên tại thời điểm đó. RAII trở thành một yêu cầu thực tế bởi vì nó không khả thi về mặt con người để dự đoán từng dòng mã có thể đưa ra các ví dụ không tầm thường (không đề cập đến việc các dòng đó có thể không ném ngay bây giờ nhưng sau đó có thể thay đổi). Lấy một ví dụ khác:
void f(const Foo* f1)
{
Foo f2;
memcpy(&f2, f1, sizeof f2);
...
}
Mã như vậy, mặc dù nói chung là vô hại trong C, giống như sự tàn phá của địa ngục trong C ++, bởi vì các memcpy
máy ủi trên các bit và byte của các đối tượng này và bỏ qua những thứ như các hàm tạo sao chép. Chức năng như vậy thích memset
, realloc
, memcpy
, vv, trong khi các công cụ hàng ngày giữa các nhà phát triển C sử dụng để nhìn nhận sự việc theo một cách khá đồng nhất của các bit và byte trong bộ nhớ, không hài hòa với hệ thống kiểu phức tạp hơn và phong phú hơn của C ++. C ++ khuyến khích một cái nhìn trừu tượng hơn nhiều về các loại do người dùng định nghĩa.
Vì vậy, những loại điều này không còn cho phép C ++, bởi bất kỳ ai đang tìm cách sử dụng nó một cách chính xác, xem nó như một "siêu năng lực" đơn thuần của C. Những ngôn ngữ này đòi hỏi một tư duy, kỷ luật và cách suy nghĩ rất khác nhau để sử dụng một cách hiệu quả nhất .
Tôi không ở trong trại, thấy C ++ hoàn toàn tốt hơn về mọi mặt và thực tế hầu hết các lib của bên thứ ba yêu thích của tôi là thư viện C vì một số lý do. Tôi không biết tại sao chính xác nhưng C libs có xu hướng tối giản hơn về bản chất (có lẽ vì không có hệ thống kiểu phong phú như vậy khiến các nhà phát triển tập trung hơn vào việc cung cấp chức năng tối thiểu cần thiết mà không xây dựng một số trừu tượng lớn và nhiều lớp), mặc dù tôi thường chỉ đặt các trình bao bọc C ++ xung quanh chúng để đơn giản hóa và điều chỉnh việc sử dụng chúng cho mục đích của tôi, nhưng bản chất tối giản đó thích hợp với tôi ngay cả khi làm điều đó. Tôi thực sự yêu thích sự tối giản như một tính năng hấp dẫn của một thư viện dành cho những người dành thêm thời gian để tìm kiếm những phẩm chất như vậy và có lẽ C có xu hướng khuyến khích điều đó,
Tôi thích C ++ thường xuyên hơn không, nhưng tôi thực sự bắt buộc phải sử dụng API C thường xuyên hơn để tương thích nhị phân rộng nhất (và cho FFI), mặc dù tôi thường triển khai chúng trong C ++ mặc dù sử dụng C cho các tiêu đề. Nhưng đôi khi khi bạn thực sự ở mức độ thấp, như mức phân bổ bộ nhớ hoặc cấu trúc dữ liệu ở mức rất thấp (và tôi chắc chắn có những ví dụ khác trong số những người làm lập trình nhúng), đôi khi có thể hữu ích khi có thể giả định rằng các loại và dữ liệu bạn đang làm việc không có các tính năng nhất định như vtables, trình xây dựng và hàm hủy, để chúng ta có thể coi chúng là các bit và byte để xáo trộn xung quanh, sao chép, miễn phí, phân bổ lại. Đối với các vấn đề rất đặc biệt ở cấp độ thấp, đôi khi có thể hữu ích khi làm việc với hệ thống loại đơn giản hơn nhiều mà C cung cấp,
Một sự làm rõ
Một nhận xét thú vị ở đây tôi muốn trả lời sâu hơn một chút (tôi thấy các nhận xét ở đây rất nghiêm ngặt về giới hạn ký tự):
memcpy(&f2, f1, sizeof f2);
cũng là "sự tàn phá địa ngục" trong C nếu Foo có bất kỳ con trỏ sở hữu nào, hoặc thậm chí tệ hơn, vì bạn cũng thiếu các công cụ để đối phó với điều đó.
Đó là một điểm công bằng nhưng tất cả mọi thứ tôi tập trung chủ yếu tập trung vào hệ thống loại của C ++ và cũng liên quan đến RAII. Một trong những lý do sao chép byte x-rayish memcpy
hoặc qsort
các loại chức năng gây ra ít nguy hiểm thực tế trong C là sự phá hủy f1
và f2
ở trên là rõ ràng (nếu chúng thậm chí cần phá hủy không tầm thường), trong khi khi các hàm hủy di chuyển vào hình ảnh , chúng trở nên tiềm ẩn và tự động (thường có giá trị lớn cho các nhà phát triển). Điều đó thậm chí không đề cập đến trạng thái ẩn như vptrs và do đó các chức năng như vậy sẽ ủi đất ngay. Nếu f1
sở hữu con trỏ vàf2
cạn bản sao chúng trong một số bối cảnh tạm thời, sau đó nó không có vấn đề gì nếu chúng ta không cố gắng giải phóng rõ ràng những người sở hữu con trỏ lần thứ hai. Với C ++, đó là điều mà trình biên dịch sẽ tự động muốn làm.
Và điều đó càng trở nên lớn hơn nếu điển hình là trong C, " Nếu Foo có sở hữu con trỏ", bởi vì nhân chứng cần thiết với quản lý tài nguyên thường sẽ khiến điều gì đó thường khó bỏ qua hơn trong khi trong C ++, chúng ta có thể khiến UDT không còn tầm thường nữa có thể xây dựng / phá hủy bằng cách chỉ làm cho nó lưu trữ bất kỳ biến thành viên nào không thể xây dựng / phá hủy một cách tầm thường (theo cách nói chung là rất hữu ích, nhưng không phải nếu chúng ta muốn sử dụng các chức năng như memcpy
hoặc realloc
).
Quan điểm chính của tôi là không cố gắng tranh luận bất kỳ lợi ích nào của nhà thám hiểm này (tôi sẽ nói nếu có bất kỳ điều gì, họ hầu như luôn bị đè nặng bởi những khuyết điểm về xác suất gia tăng của lỗi con người đi kèm với nó), mà chỉ nói rằng các chức năng như memcpy
và memmove
và qsort
và memset
vàrealloc
và v.v. không có chỗ trong một ngôn ngữ có UDT phong phú về tính năng và khả năng như C ++. Mặc dù chúng tồn tại bất kể, tôi nghĩ sẽ không quá tranh cãi khi nói rằng đại đa số các nhà phát triển C ++ sẽ là khôn ngoan để tránh các chức năng như bệnh dịch, trong khi đó là các loại chức năng rất hàng ngày trong C, và tôi d lập luận rằng họ đặt ra ít vấn đề hơn trong C vì lý do đơn giản là hệ thống loại của nó cơ bản hơn rất nhiều và có lẽ là "ngu ngốc". Các loại C tia X và coi chúng là bit và byte dễ bị lỗi. Làm điều đó trong C ++ được cho là hoàn toàn sai lầm vì các chức năng như vậy đang chống lại các tính năng rất cơ bản của ngôn ngữ và những gì nó khuyến khích của hệ thống loại.
Đó thực sự là điểm hấp dẫn nhất đối với tôi của C, tuy nhiên, đặc biệt với cách nó liên quan đến khả năng tương tác ngôn ngữ. Sẽ rất khó khăn hơn nhiều để làm cho một cái gì đó như FFI của C # hiểu được hệ thống loại hoàn chỉnh và các tính năng ngôn ngữ của C ++ xuống các hàm tạo, hàm hủy, ngoại lệ, hàm ảo, nạp chồng hàm / phương thức, quá tải toán tử, tất cả các loại khác nhau của kế thừa, v.v ... Với C, một ngôn ngữ tương đối bẩn thỉu đã trở nên khá chuẩn đối với API theo cách mà nhiều ngôn ngữ khác nhau có thể nhập trực tiếp qua FFI hoặc gián tiếp thông qua một số hàm xuất API C ở dạng mong muốn (ví dụ: Giao diện gốc Java ). Và đó là nơi tôi hầu như không còn lựa chọn nào khác ngoài sử dụng C, vì khả năng tương tác ngôn ngữ đó là một yêu cầu thiết thực trong trường hợp của chúng tôi (mặc dù tôi thường
Nhưng bạn biết đấy, tôi là một người thực dụng (hoặc ít nhất là tôi phấn đấu). Nếu C là ngôn ngữ khó chịu và đáng tin cậy, dễ bị lỗi, khó chịu nhất này, một số đồng nghiệp đam mê C ++ của tôi đã tuyên bố đó là (và tôi tự coi mình là người đam mê C ++ ngoại trừ việc bằng cách nào đó nó không dẫn đến sự ghét bỏ C ; ngược lại, nó có tác dụng ngược lại đối với tôi khi khiến tôi đánh giá cao cả hai ngôn ngữ tốt hơn ở khía cạnh và sự khác biệt của chúng), sau đó tôi hy vọng rằng nó sẽ xuất hiện trong thế giới thực dưới dạng một số lỗi và rò rỉ nhất và các sản phẩm và thư viện không đáng tin cậy được viết bằng C. Và tôi không tìm thấy điều đó. Tôi thích Linux, tôi thích Apache, Lua, zlib, tôi thấy OpenGL có thể chấp nhận được vì di sản lâu dài của nó chống lại các yêu cầu phần cứng thay đổi như vậy, Gimp, libpng, Cairo, v.v. Ít nhất là bất cứ điều gì cản trở ngôn ngữ đặt ra dường như không gây ra sự bế tắc khi viết một số thư viện và sản phẩm tuyệt vời trong tay có thẩm quyền, và đó thực sự là tất cả những gì tôi quan tâm. Vì vậy, tôi chưa bao giờ là người quan tâm đến đam mê nhất chiến tranh ngôn ngữ, ngoại trừ để tạo ra một sự hấp dẫn thực dụng và nói, "Này, có những thứ hay ho ở ngoài kia! Hãy tìm hiểu cách họ tạo ra nó và có thể có những bài học hay, không quá đặc trưng cho bản chất thành ngữ của ngôn ngữ, mà chúng ta có thể mang lại với bất kỳ ngôn ngữ nào chúng tôi đang sử dụng. " : -D