2016-02-13 17 views
7
class Test { 

public: 

    int n1; 

}; 

Test func() { 

    return Test(); 

} 

int main() { 

    func() = Test(); 

} 

Điều này không có ý nghĩa với tôi. Làm thế nào và tại sao điều này được cho phép? Đó là hành vi không xác định? Nếu một hàm trả về một giá trị, thì làm thế nào để có thể thiết lập một giá trị rvalue sang một giá trị khác? Nếu tôi thử điều này với bất kỳ kiểu nguyên thủy nào, nó sẽ cho tôi một lỗi như tôi mong đợi.Chỉ định Rvalue được trả về từ hàm này sang hàm Rvalue khác

Tôi biết rằng giá trị là một vị trí trong bộ nhớ, do đó, chức năng tạo ra một giá trị tạm thời (rvalue?) Và gán nó cho một giá trị khác? Ai đó có thể giải thích cách cú pháp này hoạt động?

+0

"_Nếu một hàm trả về một rvalue_" Nó không. – curiousguy

Trả lời

6

Danh mục giá trị của biểu thức cuộc gọi hàm thực tế là một giá trị.

Thật vậy, bạn không thể gọi toán tử gán bản sao trên nguyên thủy giá trị. Định nghĩa lịch sử về các giá trị trong C thực ra là sự khác biệt rằng chúng có thể không ở bên trái của một sự xác nhận.

Các toán tử gán của các lớp có một chút khác biệt. Chúng là các hàm thành viên thông thường. Và không có quy tắc nào ngăn cản các hàm thành viên của các giá trị. Thật vậy, nó thường khá hữu ích khi các chức năng có tác dụng phụ.

Cách thức hoạt động, tốt, toán tử gán bản sao được gọi tạm thời, toán tử sao chép đối số tay phải, thay đổi trạng thái tạm thời. Sau khi tuyên bố, đối tượng tạm thời bị loại bỏ. Không có UB, chỉ cần sao chép vô nghĩa.

Bạn có thể ngăn việc gán bản sao cuộc gọi trên giá trị bằng cách khai báo toán tử với bộ định mức tham khảo như sau: Test& operator=(Test) & = default;. Các vòng loại tham chiếu chỉ được thêm vào sau trong C++ 11, do đó, (ẩn) bản sao chép bài tập không thể được chỉ định để có thể đủ điều kiện trước đó. Có lẽ, C++ 11 không thay đổi vòng loại của hàm tạo bản sao ngầm để ngăn chặn việc phá vỡ mã cũ mà gán cho một giá trị rvalue, mặc dù gán như vậy dường như khá vô nghĩa. High Integrity C++ Coding Standard khuyên bạn nên sử dụng vòng loại ref với các toán tử gán bản sao do người dùng xác định.

+0

"_Giá trị trả về của hàm thực tế là một rvalue._" Không, đối tượng trả về là một đối tượng. – curiousguy

+1

@curiousguy biểu thức đối tượng có các loại giá trị. Danh mục là giá trị r trong trường hợp này. – user2079303

+0

Tất cả các biểu thức đều có các danh mục, không chỉ các danh mục tham chiếu đến một đối tượng. Đối tượng trả về chỉ là một đối tượng, không phải là một biểu thức. – curiousguy

1

Có một đường cong học tập khá dốc đến chừng value categories có liên quan (ít nhất là với tôi), nhưng tôi tin rằng bạn đã có số terminology ngay trên ví dụ của bạn. Vì vậy,

func() 

thực sự trả về một prvalue và từ C++ mệnh Standard. 3.10.5 (tôi chỉ có dòng điện draft, số đoạn của bạn có thể thay đổi) chúng ta đọc:

Một vế trái cho một đối tượng là cần thiết để sửa đổi các đối tượng ngoại trừ rằng một rvalue của kiểu lớp có thể cũng được sử dụng để sửa đổi tham chiếu của nó trong một số trường hợp nhất định. [Ví dụ: một hàm thành viên được gọi cho đối tượng (9.3) có thể sửa đổi đối tượng. - ví dụ cuối]

Vì vậy, toán tử gán, là một hàm thành viên, như trong ví dụ được đề cập trong tiêu chuẩn là ngoại lệ cho quy tắc, cho phép sửa đổi các giá trị.

này đã sản sinh ra nhiều chỉ trích trong thế giới lập trình, với ví dụ cực đoan nhất của nó C++ FQA đoạn trích này:

(Vâng, bẫy chết bọc đường, bạn tránh khỏi thất bại cheerleaders.X& obj=a.b().c() - oops, b() là một đối tượng tạm thời và c() trả về một tham chiếu vào nó! Không nên gán nó cho một tham chiếu. . Không có nhiều cơ hội cho một cảnh báo trình biên dịch, một trong hai)

Nhưng trong C++ thực lập trình nó có industrial applications như named parameter thành ngữ:

std::cout << X::create().setA(10).setB('Z') << std::endl; 
+0

Bạn nhận được thuật ngữ sai: hàm gọi 'func()' là một giá trị, giá trị trả về không phải là. – curiousguy

Các vấn đề liên quan