GIỚI THIỆU
ISOC ++ 11 (chính thức ISO / IEC 14882: 2011) là phiên bản gần đây nhất của tiêu chuẩn của ngôn ngữ lập trình C ++. Nó chứa một số tính năng mới và các khái niệm, ví dụ:
- tài liệu tham khảo giá trị
- Các loại giá trị biểu thức xvalue, glvalue, prvalue
- di chuyển ngữ nghĩa
Nếu chúng ta muốn hiểu các khái niệm về các loại giá trị biểu thức mới, chúng ta phải nhận thức được rằng có các tham chiếu rvalue và lvalue. Tốt hơn là nên biết giá trị có thể được chuyển đến các tham chiếu giá trị không const.
int& r_i=7; // compile error
int&& rr_i=7; // OK
Chúng ta có thể có được một số trực giác về các khái niệm của các loại giá trị nếu chúng ta trích dẫn tiểu mục có giá trị Lvalues và giá trị từ dự thảo làm việc N3337 (dự thảo tương tự nhất với tiêu chuẩn ISOC ++ 11 đã xuất bản).
3.10 Giá trị và giá trị [basic.lval]
1 Biểu thức được phân loại theo phân loại trong Hình 1.
- Một giá trị (được gọi là, trong lịch sử, bởi vì giá trị có thể xuất hiện ở phía bên trái của biểu thức gán) chỉ định một chức năng hoặc một đối tượng. [Ví dụ: Nếu E là biểu thức của loại con trỏ, thì * E là biểu thức giá trị tham chiếu đến đối tượng hoặc hàm mà E trỏ tới. Một ví dụ khác, kết quả của việc gọi một hàm có kiểu trả về là tham chiếu giá trị là một giá trị. Ví dụ
- Một giá trị xvalue (một giá trị của eXpires ') cũng đề cập đến một đối tượng, thường là gần cuối vòng đời của nó (ví dụ như tài nguyên của nó có thể được di chuyển). Xvalue là kết quả của một số loại biểu thức liên quan đến tham chiếu rvalue (8.3.2). [Ví dụ: Kết quả của việc gọi một hàm có kiểu trả về là tham chiếu giá trị là xvalue. Ví dụ
- Một giá trị (giá trị chung của Lvalue) là một giá trị hoặc một giá trị xvalue.
- Một giá trị (được gọi là, theo lịch sử, bởi vì các giá trị có thể xuất hiện ở phía bên phải của biểu thức gán) là một giá trị x, một
đối tượng tạm thời (12.2) hoặc phụ của nó hoặc một giá trị không được
liên kết với một đối tượng.
- Một giá trị (giá trị thuần túy rvalue) là một giá trị không phải là một giá trị xvalue. [Ví dụ: Kết quả của việc gọi một hàm có kiểu trả về không phải là
tham chiếu là một giá trị. Giá trị của một nghĩa đen như 12, 7.3e5 hoặc
true cũng là một giá trị. Ví dụ
Mỗi biểu thức thuộc về chính xác một trong các phân loại cơ bản trong phân loại này: lvalue, xvalue hoặc prvalue. Thuộc tính này của một biểu thức được gọi là thể loại giá trị của nó.
Nhưng tôi không chắc lắm về việc tiểu mục này đủ để hiểu các khái niệm một cách rõ ràng, bởi vì "thông thường" không thực sự chung chung, "gần cuối đời" không thực sự cụ thể, "liên quan đến các tham chiếu giá trị" không thực sự rõ ràng, và "Ví dụ: Kết quả của việc gọi một hàm có kiểu trả về là tham chiếu giá trị là một giá trị x." Nghe có vẻ như một con rắn đang cắn đuôi nó.
THỂ LOẠI GIÁ TRỊ CHÍNH XÁC
Mỗi biểu thức thuộc về chính xác một loại giá trị chính. Các loại giá trị này là các loại lvalue, xvalue và prvalue.
giá trị
Biểu thức E thuộc về loại giá trị khi và chỉ khi E đề cập đến một thực thể mà ALREADY đã có một danh tính (địa chỉ, tên hoặc bí danh) làm cho nó có thể truy cập được bên ngoài E.
#include <iostream>
int i=7;
const int& f(){
return i;
}
int main()
{
std::cout<<&"www"<<std::endl; // The expression "www" in this row is an lvalue expression, because string literals are arrays and every array has an address.
i; // The expression i in this row is an lvalue expression, because it refers to the same entity ...
i; // ... as the entity the expression i in this row refers to.
int* p_i=new int(7);
*p_i; // The expression *p_i in this row is an lvalue expression, because it refers to the same entity ...
*p_i; // ... as the entity the expression *p_i in this row refers to.
const int& r_I=7;
r_I; // The expression r_I in this row is an lvalue expression, because it refers to the same entity ...
r_I; // ... as the entity the expression r_I in this row refers to.
f(); // The expression f() in this row is an lvalue expression, because it refers to the same entity ...
i; // ... as the entity the expression f() in this row refers to.
return 0;
}
giá trị
Biểu thức E thuộc về loại xvalue khi và chỉ khi nó là
- kết quả của việc gọi một hàm, dù là ngầm hay rõ ràng, kiểu trả về của nó là một tham chiếu giá trị cho loại đối tượng được trả về, hoặc
int&& f(){
return 3;
}
int main()
{
f(); // The expression f() belongs to the xvalue category, because f() return type is an rvalue reference to object type.
return 0;
}
- chuyển sang tham chiếu giá trị cho loại đối tượng, hoặc
int main()
{
static_cast<int&&>(7); // The expression static_cast<int&&>(7) belongs to the xvalue category, because it is a cast to an rvalue reference to object type.
std::move(7); // std::move(7) is equivalent to static_cast<int&&>(7).
return 0;
}
- một biểu thức truy cập thành viên lớp chỉ định một thành viên dữ liệu không tĩnh thuộc loại không tham chiếu trong đó biểu thức đối tượng là một giá trị x, hoặc
struct As
{
int i;
};
As&& f(){
return As();
}
int main()
{
f().i; // The expression f().i belongs to the xvalue category, because As::i is a non-static data member of non-reference type, and the subexpression f() belongs to the xvlaue category.
return 0;
}
- một biểu thức con trỏ đến thành viên trong đó toán hạng thứ nhất là một giá trị x và toán hạng thứ hai là một con trỏ tới thành viên dữ liệu.
Lưu ý rằng tác dụng của các quy tắc ở trên là các tham chiếu rvalue có tên đến các đối tượng được coi là giá trị và tham chiếu rvalue không tên cho các đối tượng được coi là xvalues; tham chiếu giá trị cho các hàm được coi là giá trị cho dù có tên hay không.
#include <functional>
struct As
{
int i;
};
As&& f(){
return As();
}
int main()
{
f(); // The expression f() belongs to the xvalue category, because it refers to an unnamed rvalue reference to object.
As&& rr_a=As();
rr_a; // The expression rr_a belongs to the lvalue category, because it refers to a named rvalue reference to object.
std::ref(f); // The expression std::ref(f) belongs to the lvalue category, because it refers to an rvalue reference to function.
return 0;
}
giá trị
Biểu thức E thuộc về loại giá trị khi và chỉ khi E không thuộc loại giá trị cũng không thuộc loại xvalue.
struct As
{
void f(){
this; // The expression this is a prvalue expression. Note, that the expression this is not a variable.
}
};
As f(){
return As();
}
int main()
{
f(); // The expression f() belongs to the prvalue category, because it belongs neither to the lvalue nor to the xvalue category.
return 0;
}
PHÂN LOẠI GIÁ TRỊ
Có hai loại giá trị hỗn hợp quan trọng hơn nữa. Các loại giá trị này là các loại giá trị và giá trị.
giá trị
Biểu thức E thuộc về loại giá trị khi và chỉ khi E thuộc loại xvalue hoặc thuộc loại prvalue.
Lưu ý rằng định nghĩa này có nghĩa là biểu thức E thuộc về loại giá trị khi và chỉ khi E đề cập đến một thực thể không có bất kỳ danh tính nào làm cho nó có thể truy cập được bên ngoài E YET.
giá trị
Biểu thức E thuộc danh mục glvalue khi và chỉ khi E thuộc danh mục lvalue hoặc thuộc danh mục xvalue.
MỘT QUY TẮC THỰC HÀNH
Scott Meyer đã xuất bản một quy tắc rất hữu ích để phân biệt giá trị với giá trị.
- Nếu bạn có thể lấy địa chỉ của một biểu thức, biểu thức là một giá trị.
- Nếu loại biểu thức là tham chiếu giá trị (ví dụ: T & hoặc const T &, v.v.), thì biểu thức đó là một giá trị.
- Mặt khác, biểu thức là một giá trị. Về mặt khái niệm (và thường là trên thực tế), các giá trị tương ứng với các đối tượng tạm thời, chẳng hạn như các đối tượng được trả về từ các hàm hoặc được tạo thông qua các chuyển đổi kiểu ẩn. Hầu hết các giá trị theo nghĩa đen (ví dụ 10 và 5,3) cũng là giá trị.