2010-02-19 25 views
21

Bất kỳ ai có thể giải thích chi tiết về tỷ lệ, giá trị, POD và không phải POD là lý do tại sao biểu thức đầu tiên được đánh dấu bên dưới là không phải là. được? Trong sự hiểu biết của tôi cả int() và A() nên được rvalues, không?PODs, không phải POD, rvalue và lvalues ​​


struct A {}; 

int main() 
{ 
    int i; 
    A a; 

    int() = i; //Not OK (error). 
    A() = a; //OK. 

    return 0; 
} 

Trả lời

17

Rvalues ​​là những gì bạn nhận được từ biểu thức (đơn giản hóa hữu ích lấy từ tiêu chuẩn C, nhưng không diễn đạt trong C++ tiêu chuẩn). Giá trị là "giá trị định vị". Các giá trị có thể được sử dụng làm giá trị. Tham chiếu luôn là các giá trị, ngay cả khi const.

Sự khác biệt chính mà bạn phải biết là có thể được cô đặc thành một mục: bạn không thể lấy địa chỉ của một giá trị (một lần nữa, không phải là tiêu chuẩn nhưng là khái quát hóa các quy tắc hữu ích). Hoặc để đặt theo cách khác, bạn không thể sửa một địa điểm chính xác để nhận giá trị — nếu có thể, sau đó bạn sẽ có lvalue. (Tuy nhiên, bạn có thể liên kết một const & với một giá trị để "sửa chữa nó tại chỗ", và 0x đang thay đổi các quy tắc quyết liệt.)

Kiểu do người dùng định nghĩa (UDT), tuy nhiên, hơi đặc biệt: bạn có thể chuyển đổi bất kỳ rvalue vào một giá trị trái, nếu giao diện của lớp cho phép nó:

struct Special { 
    Special& get_lvalue() { return *this; } 
}; 
void f() { 
    // remember "Special()" is an rvalue 
    Special* p = &Special().get_lvalue(); // even though you can't dereference the 
    // pointer (because the object is destroyed), you still just took the address 
    // of a temporary 

    // note that the get_lvalue() method doesn't need to operate on a const 
    // object (though that would be fine too, if the return type matched) 
} 

Something tương tự đang xảy ra cho A() = a của bạn, ngoại trừ thông qua toán tử gán trình biên dịch cung cấp, để biến rvalue A() vào *this. Để trích dẫn tiêu chuẩn, 12,8/10:

Nếu định nghĩa lớp không tuyên bố một cách rõ ràng một toán tử gán sao chép, một tuyên bố ngầm. Các ngầm-tuyên bố tử gán bản sao cho một lớp X sẽ có dạng

X& X::operator=(const X&) 

Và sau đó nó đi vào với nhiều trình độ và thông số kỹ thuật, nhưng đó là các bit quan trọng ở đây. Vì đó là một hàm thành viên, nó có thể được gọi trên giá trị, giống như Special :: get_lvalue có thể, như thể bạn đã viết A().operator=(a) thay vì A() = a.

int() = 1 bị cấm hoàn toàn khi bạn phát hiện ra, vì int không có toán tử = được triển khai theo cùng một cách. Tuy nhiên, sự khác biệt nhỏ giữa các loại không quan trọng trong thực tế (ít nhất là không phải là tôi đã tìm thấy).


POD có nghĩa là Dữ liệu cũ thuần túy và là tập hợp các yêu cầu chỉ định bằng memcpy tương đương với sao chép. Không phải POD là bất kỳ loại nào mà bạn không thể sử dụng memcpy để sao chép (đối diện tự nhiên của POD, không có gì ẩn ở đây), có xu hướng là hầu hết các loại bạn sẽ viết bằng C++. Là POD hoặc không phải POD không thay đổi bất kỳ điều nào ở trên, và thực sự là một vấn đề riêng biệt.

+0

C-cụ thể, nhưng vẫn hữu ích cho các lập trình viên C++ để hiểu: http://stackoverflow.com/questions/2038414/lvalue-and-rvalue/2038427#2038427. (Đây là một khu vực cả hai ngôn ngữ về cơ bản chia sẻ, mặc dù C++ khá phức tạp hơn với các tham chiếu và thực sự sử dụng thuật ngữ "rvalue" mà C không còn nữa.) –

+0

"_Or để đặt nó theo cách khác, bạn không thể sửa chữa một vị trí chính xác cho một rvalue_ "theo tiêu chuẩn ngôn ngữ, một rvalue của loại cơ bản thậm chí không phải là một đối tượng, và không có một địa chỉ. – curiousguy

1

Từ Does C++ do value initialization of a POD typedef?, mà trích dẫn tiêu chuẩn:

Khái niệm T(), trong đó T là một đơn giản-type-specifier (7.1.5.2) cho một đối tượng hoàn chỉnh không cho mảng loại hoặc (có thể cv-đủ điều kiện) kiểu void, tạo ra một rvalue của quy định loại, đó là giá trị khởi tạo

Vì vậy int() là một giá trị và không thể được gán cho, như bạn đã thấy trong trường hợp đầu tiên của bạn.

A() sẽ không là một simlle-type-specifyer và do đó A() mang lại một giá trị trái

+2

Liên kết đi theo vòng tròn đến trang này. §5.2.3 quy định rõ ràng rằng T() là một giá trị bất cứ loại nào. – Potatoswatter

+0

Cố định liên kết - lỗi trong FireFox (nó không cập nhật thanh địa chỉ khi chuyển đổi tab) – DVK

+2

Ngay cả với liên kết sai, câu trả lời sẽ chính xác vì liên kết trỏ tới trang có liên kết đến trang có liên kết đến trang ... với trích dẫn. Tệ quá, nó không phải là đệ quy đuôi. :-). –

2

Trong sự hiểu biết của tôi cả int() và A() phải là giá trị, phải không?

Chính xác, epxression T() luôn là giá trị cho vô hướng và các loại do người dùng xác định T. Miễn là không có const có liên quan, biểu thức T() là một giá trị sửa đổi có thể sửa đổi được, để chính xác hơn.

Việc gán liên quan đến các loại vô hướng yêu cầu có thể sửa đổi lvalue ở phía bên tay trái của toán tử gán. Vì int() không phải là một giá trị, bạn không thể chỉ định cho int().

Đối với các loại do người dùng xác định, nhiệm vụ là chức năng thành viên đặc biệt và chức năng thành viên cũng có thể được gọi theo số rvalues ​​ (xem §3.10 phần 10). Đó là lý do tại sao A().operator=(a) cũng được hình thành.

+0

'int()' là một giá trị _modifiable rvalue_? – curiousguy

+0

@curiousguy: Có. [Không có giá trị vô hướng const] (http://stackoverflow.com/questions/2169932/). – fredoverflow

+0

Làm cách nào để sửa đổi? – curiousguy

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