Tôi không đồng ý với câu "Tôi nghĩ tốt nhất là không nên dựa vào tối ưu hóa trình biên dịch để làm cho mã của bạn hoạt động hiệu quả". Đó là cơ bản toàn bộ công việc của trình biên dịch. Công việc của bạn là viết mã nguồn rõ ràng, chính xác và có thể duy trì được. Đối với mọi vấn đề hiệu suất mà tôi từng phải khắc phục, tôi đã phải sửa chữa một trăm vấn đề trở lên do nhà phát triển cố gắng thông minh thay vì thực hiện điều gì đó đơn giản, chính xác và có thể bảo trì.
Hãy xem một số điều bạn có thể làm để cố gắng "giúp" trình biên dịch và xem chúng ảnh hưởng như thế nào đến khả năng bảo trì của mã nguồn.
- Bạn có thể trả lại dữ liệu thông qua tham khảo
Ví dụ:
void hello(std::string& outString)
Trở dữ liệu sử dụng một tài liệu tham khảo làm cho mã tại các cuộc gọi tại chỗ khó đọc.Nó gần như không thể nói những gì gọi là trạng thái đột biến như là một tác dụng phụ và không. Ngay cả khi bạn thực sự cẩn thận với const đủ điều kiện tham khảo nó sẽ khó đọc tại trang web cuộc gọi. Hãy xem xét ví dụ sau:
void hello(std::string& outString); //<-This one could modify outString
void out(const std::string& toWrite); //<-This one definitely doesn't.
. . .
std::string myString;
hello(myString); //<-This one maybe mutates myString - hard to tell.
out(myString); //<-This one certainly doesn't, but it looks identical to the one above
Thậm chí tuyên bố chào không rõ ràng. Liệu nó sửa đổi outString, hoặc là tác giả chỉ cẩu thả và quên const đủ điều kiện tham chiếu? Mã được viết trong một functional style dễ đọc và dễ hiểu hơn để vô tình phá vỡ.
Tránh
- Bạn có thể trả về một con trỏ đến đối tượng thay vì trả lại đối tượng.
Trả về một con trỏ đến đối tượng khiến bạn khó chắc chắn mã của mình là chính xác. Trừ khi bạn sử dụng unique_ptr, bạn phải tin tưởng rằng bất cứ ai sử dụng phương pháp của bạn là kỹ lưỡng và chắc chắn để xóa con trỏ khi họ đang thực hiện với nó, nhưng đó không phải là rất RAII. std :: string đã là một loại trình bao bọc RAII cho một char * tóm tắt các vấn đề về tuổi thọ dữ liệu liên quan đến việc trả về một con trỏ. Trả về một con trỏ tới một std :: string chỉ giới thiệu lại các vấn đề mà std :: string được thiết kế để giải quyết. Dựa vào một con người để được siêng năng và đọc kỹ các tài liệu cho chức năng của bạn và biết khi nào để xóa con trỏ và khi không xóa con trỏ thì không có kết quả tích cực.
Tránh
- đó mang lại cho chúng ta di chuyển nhà xây dựng.
Một hàm tạo di chuyển sẽ chỉ chuyển quyền sở hữu dữ liệu được trỏ đến từ 'kết quả' đến đích cuối cùng của nó. Sau đó, việc truy cập đối tượng 'kết quả' không hợp lệ nhưng điều đó không quan trọng - phương thức của bạn đã kết thúc và đối tượng 'kết quả' nằm ngoài phạm vi. Không sao chép, chỉ cần chuyển quyền sở hữu của con trỏ với ngữ nghĩa rõ ràng.
Thông thường trình biên dịch sẽ gọi hàm khởi tạo di chuyển cho bạn. Nếu bạn thực sự hoang tưởng (hoặc có kiến thức cụ thể rằng trình biên dịch sẽ không giúp bạn), bạn có thể sử dụng std::move.
Thực hiện một trong này nếu có thể
Cuối cùng trình biên dịch hiện đại là tuyệt vời. Với trình biên dịch C++ hiện đại, 99% thời gian trình biên dịch sẽ thực hiện một số loại tối ưu hóa để loại bỏ bản sao. 1% thời gian khác có lẽ sẽ không thành vấn đề về hiệu suất. Trong những trường hợp cụ thể, trình biên dịch có thể viết lại một phương thức như std :: string GetString(); để void GetString (std :: string & outVar); tự động. Mã này vẫn còn dễ đọc, nhưng trong hội đồng cuối cùng bạn nhận được tất cả các lợi ích tốc độ thực hoặc tưởng tượng của trở lại bằng cách tham khảo. Đừng hy sinh khả năng đọc và bảo trì cho hiệu suất trừ khi bạn có kiến thức cụ thể rằng giải pháp không đáp ứng các yêu cầu kinh doanh của bạn.
Không tối ưu hóa cho đến khi bạn xác nhận rằng giải pháp của bạn không đáp ứng được các yêu cầu kinh doanh và sau đó chỉ tối ưu hóa những gì mà trình lược tả cho bạn biết là quá chậm. Hãy để trình biên dịch xử lý nó. Nó sẽ dễ dàng hơn để đọc và duy trì. –
Trong C++ 11 điều này gần như chắc chắn sẽ sử dụng một nhà xây dựng di chuyển nếu vì một số lý do RVO không thành công. Nếu bạn muốn hoàn toàn chắc chắn, vượt qua chuỗi đầu ra trong tham chiếu thay vì trả lại nó. RVO là một phần của tiêu chuẩn bây giờ mặc dù vậy miễn là bạn có một trình biên dịch hiện đại, bạn thường có thể dựa vào nó. –
@PeteBaughman và Jonathan Potter: Tôi nhận ra rằng trình biên dịch có thể tối ưu hóa điều này, và điều này có thể không gây ra chi phí lớn trong ứng dụng của tôi, nhưng không thể thực hiện điều này một cách cơ bản theo nghĩa? –