2009-09-08 9 views
23

Vui lòng xem xét ba hàm.Hiểu tối ưu hóa giá trị trả về và thời gian trả về - C++

std::string get_a_string() 
{ 
    return "hello"; 
} 

std::string get_a_string1() 
{ 
    return std::string("hello"); 
} 

std::string get_a_string2() 
{ 
    std::string str("hello"); 
    return str; 
} 
  1. sẽ RVO được áp dụng trong tất cả ba trường hợp?
  2. Có thể trả lại mã tạm thời giống như mã trên không? Tôi tin rằng nó là OK vì tôi trả lại nó bằng giá trị hơn là trả lại bất kỳ tham chiếu đến nó.

Bạn nghĩ gì?

Trả lời

16

Trong hai trường hợp đầu tiên, tối ưu hóa RVO sẽ diễn ra. RVO là tính năng cũ và hầu hết các trình biên dịch đều hỗ trợ nó. Trường hợp cuối cùng được gọi là NRVO (RVO có tên). Đó là tính năng tương đối mới của C++. Tiêu chuẩn cho phép, nhưng không yêu cầu thực hiện NRVO (cũng như RVO), nhưng một số trình biên dịch hỗ trợ nó.

Bạn có thể đọc thêm về RVO trong mục 20 của sách Scott Meyers More Effective C++. 35 New Ways to Improve Your Programs and Designs.

Here là một bài viết tốt về NRVO trong Visual C++ 2005.

+0

Có cách nào trong VS2008 để tắt tất cả các tối ưu hóa bao gồm RVO? Tôi đã tắt tất cả nhưng nó vẫn đang làm RVO. Đây chỉ là để hiểu sự khác biệt. –

+0

'/ Od' nên tắt NRVO, nhưng tôi không chắc về RVO. –

+0

Cảm ơn. Hãy để tôi thử rằng –

7

Trước tiên, bạn hoàn toàn có thể trả lại giá trị tạm thời theo giá trị mà bạn làm. Nó được sao chép và mặc dù bản gốc sẽ đi ra khỏi phạm vi bản sao sẽ không làm như vậy và có thể được sử dụng một cách an toàn bởi người gọi.

Thứ hai, cả ba trường hợp đều giống nhau (vì bạn không truy cập tạm thời trong trường hợp thứ ba) và trình biên dịch thậm chí có thể phát ra cùng một mã cho tất cả chúng. Do đó nó có thể sử dụng RVO trong cả ba trường hợp. Điều này hoàn toàn phụ thuộc vào trình biên dịch.

+0

Cảm ơn bạn đã trả lời. –

1
  1. Tùy thuộc vào trình biên dịch của bạn - bạn đang đề cập đến nền tảng nào? Cách tốt nhất để tìm hiểu là biên dịch rất ứng dụng thử nghiệm nhỏ và kiểm tra ASM trình biên dịch của bạn tạo ra.

  2. Có, không sao, mặc dù bạn không bao giờ đề cập đến những gì bạn quan tâm; tốc độ? Phong cách? bạn có thể một địa phương tạm thời để tham chiếu const - tuổi thọ của tạm thời sẽ được mở rộng đến tuổi thọ của tài liệu tham khảo - hãy thử nó và xem cho chính mình! (Herb Sutter exaplins này here) Xem kết thúc của bài ví dụ.

IMO bạn gần như luôn tin tưởng vào trình biên dịch để tối ưu hóa mã cho bạn. Có rất ít trường hợp mà bạn cần phải quan tâm về loại điều này (mã mức rất thấp là một trong những khu vực như vậy, nơi bạn tương tác với các thanh ghi phần cứng).

int foo() { return 42; } 

int main(int, char**) 
{ 
    const int &iRef = foo(); 
    // iRef is valid at this point too! 
} 
+4

"bạn có thể trả lại tham chiếu const cho một địa phương tạm thời" không có gì sai. Bạn không thể trả về một tham chiếu đến một cục bộ hoặc các thời gian được tạo trong hàm đó. Chúng sẽ bị hủy khi hàm trả về, và giá trị trả về tham chiếu sẽ chỉ đến rác. Tôi nghĩ bạn có 'const T & t = T(); 'trong tâm trí, đó là một vấn đề khác. –

+0

Vâng, đó là những gì tôi có trong tâm trí. Tôi đã làm cho rõ ràng hơn bây giờ. – Thomi

2

Mọi trường hợp đều đúng. Tất cả chúng sẽ xây dựng tạm thời và áp dụng hàm tạo bản sao của kiểu trả về. Nhất thiết, nếu không có hàm tạo bản sao, mã sẽ thất bại.

RVO sẽ xảy ra trên cả ba trường hợp theo hầu hết các trình biên dịch. Chỉ có sự khác biệt là tiêu chí cuối cùng mà tiêu chuẩn không ép buộc nó. Điều này bởi vì bạn có một biến được đặt tên. Nhưng hầu hết các trình biên dịch đủ thông minh để áp dụng RVO cho nó vẫn ... sau đó biến được đặt tên được khai báo và biến đổi ít được áp dụng, tỷ lệ cược tốt hơn cho RVO được áp dụng cho biến được đặt tên.

Ngẫu nhiên, việc trả về một tham chiếu là tất nhiên có thể như bạn có thể đã thấy trong mã khác. Những gì bạn không phải làm là trả về một tham chiếu t một đối tượng cục bộ.

std::string& get_a_string2() 
{ 
    std::string str("hello"); 
    return str; //error! 
} 

Sẽ tạo ra lỗi thời gian biên dịch, như bạn đã biết. Tuy nhiên,

std::string& get_a_string2(std::string& str) 
{ 
    // do something to str 
    return str; //OK 
} 

Sẽ hoạt động tốt. Trong trường hợp này, không có công trình xây dựng hoặc bản sao nào liên quan. Đơn giản chỉ cần hàm trả về một tham chiếu đến đối số của nó.

+1

Tuy nhiên, tôi muốn có chức năng đó như là một khoảng trống và không trả lại gì vì nó xử lý thông số. Trả lại tham số tham chiếu sẽ chỉ gây nhầm lẫn cho người khác khi xem mã. –

+1

có. Đó chỉ là một ví dụ minh họa. –