Tuyên bố gì
return {};
trong C ++ 11 chỉ ra và khi nào nên sử dụng nó thay vì (nói)
return NULL;
hoặc là
return nullptr;
return;
không có giá trị?
return;
Mặt khác return{};
là hợp lệ nếu bạn có loại trả về.
Tuyên bố gì
return {};
trong C ++ 11 chỉ ra và khi nào nên sử dụng nó thay vì (nói)
return NULL;
hoặc là
return nullptr;
return;
không có giá trị?
return;
Mặt khác return{};
là hợp lệ nếu bạn có loại trả về.
Câu trả lời:
return {};
cho biết "trả về một đối tượng của kiểu trả về của hàm được khởi tạo với một trình khởi tạo danh sách trống ". Hành vi chính xác phụ thuộc vào loại đối tượng được trả về.
Từ cppreference.com (vì OP được gắn thẻ C ++ 11, tôi đã loại trừ các quy tắc trong C ++ 14 và C ++ 17; tham khảo liên kết để biết thêm chi tiết):
- Nếu danh sách braces-init-trống và T là một loại lớp với hàm tạo mặc định, việc khởi tạo giá trị được thực hiện.
- Mặt khác, nếu T là loại tổng hợp, việc khởi tạo tổng hợp được thực hiện.
- Mặt khác, nếu T là một chuyên môn của std :: initizer_list, thì đối tượng T được khởi tạo trực tiếp hoặc khởi tạo sao chép, tùy thuộc vào ngữ cảnh, từ danh sách braces-init-list.
Mặt khác, các hàm tạo của T được xem xét, theo hai giai đoạn:
- Tất cả các hàm tạo lấy std :: initizer_list làm đối số duy nhất hoặc làm đối số đầu tiên nếu các đối số còn lại có giá trị mặc định, được kiểm tra và khớp với độ phân giải quá tải đối với một đối số kiểu std :: initizer_list
- Nếu giai đoạn trước không tạo ra sự trùng khớp, tất cả các nhà xây dựng của T tham gia giải quyết quá tải đối với tập hợp các đối số bao gồm các thành phần của danh sách khởi tạo, với hạn chế chỉ cho phép chuyển đổi không thu hẹp. Nếu giai đoạn này tạo ra một hàm tạo rõ ràng là kết hợp tốt nhất cho khởi tạo danh sách sao chép, thì quá trình biên dịch không thành công (lưu ý, trong khởi tạo sao chép đơn giản, các hàm tạo rõ ràng hoàn toàn không được xem xét).
Mặt khác (nếu T không phải là loại lớp), nếu danh sách braces-init-list chỉ có một phần tử và T không phải là loại tham chiếu hoặc là loại tham chiếu tương thích với loại phần tử, T là trực tiếp- khởi tạo (trong khởi tạo danh sách trực tiếp) hoặc khởi tạo sao chép (trong khởi tạo danh sách sao chép), ngoại trừ việc thu hẹp chuyển đổi không được phép.
- Mặt khác, nếu T là loại tham chiếu không tương thích với loại phần tử. (điều này không thành công nếu tham chiếu là tham chiếu lvalue không const)
- Mặt khác, nếu danh sách braces-init-list không có phần tử, T được khởi tạo giá trị.
Trước C ++ 11, đối với hàm trả về a std::string
, bạn sẽ viết:
std::string get_string() {
return std::string();
}
Sử dụng cú pháp cú đúp trong C ++ 11, bạn không cần lặp lại kiểu:
std::string get_string() {
return {}; // an empty string is returned
}
return NULL
và return nullptr
nên được sử dụng khi hàm trả về một loại con trỏ:
any_type* get_pointer() {
return nullptr;
}
Tuy nhiên, NULL
không được dùng nữa vì C ++ 11 vì nó chỉ là bí danh cho một giá trị nguyên (0), trong khi đó nullptr
là một loại con trỏ thực:
int get_int() {
return NULL; // will compile, NULL is an integer
}
int get_int() {
return nullptr; // error: nullptr is not an integer
}
Điều này có lẽ khó hiểu:
int foo()
{
return {}; // honestly, just return 0 - it's clearer
}
Đây có lẽ là không:
SomeObjectWithADefaultConstructor foo()
{
return {};
// equivalent to return SomeObjectWithADefaultConstructor {};
}
initializer_list
tạo, sẽ không được sử dụng nếu không có hàm tạo mặc định nào khả dụng?
return {}
KHÔNG tương đương vớireturn SomeObjectWithADefaultConstructor{};
return {};
có nghĩa {}
là bộ khởi tạo cho giá trị trả về . Giá trị trả về được khởi tạo danh sách với một danh sách trống.
Dưới đây là một số thông tin cơ bản về giá trị trả về , dựa trên [stmt.return] trong Tiêu chuẩn C ++:
Đối với một hàm trả về theo giá trị (nghĩa là kiểu trả về không phải là tham chiếu và không void
), có một đối tượng tạm thời được gọi là giá trị trả về . Đối tượng này được tạo bởi return
câu lệnh và các khởi tạo của nó phụ thuộc vào những gì trong câu lệnh return.
Giá trị trả về tồn tại cho đến khi kết thúc biểu thức đầy đủ trong mã được gọi là hàm; nếu nó có kiểu lớp, thì hàm hủy của nó sẽ chạy trừ khi nó được kéo dài suốt đời bởi người gọi ràng buộc một tham chiếu trực tiếp đến nó.
Giá trị trả về có thể được khởi tạo theo hai cách khác nhau:
return some_expression;
- giá trị trả về được sao chép khởi tạo từsome_expression
return { possibly_empty_list };
- giá trị trả về được
khởi tạo danh sách từ danh sách.Giả sử T
là kiểu trả về của hàm, sau đó lưu ý return T{};
khác với return {}
: trước đây, tạm thời T{}
được tạo và sau đó giá trị trả về được sao chép khởi tạo từ tạm thời đó.
Điều này sẽ không biên dịch được nếu T
không có bản sao / move-constructor có thể truy cập được, nhưng return {};
sẽ thành công ngay cả khi những hàm tạo đó không có mặt. Theo đó, return T{};
có thể hiển thị các tác dụng phụ của trình tạo bản sao, v.v., mặc dù đây là bối cảnh bầu chọn sao chép nên có thể không.
Đây là một bản tóm tắt ngắn gọn về khởi tạo danh sách trong C ++ 14 (N4140 [dcl.init.list] / 3), trong đó trình khởi tạo là một danh sách trống:
T
là một tổng hợp, thì mỗi thành viên được khởi tạo từ bộ khởi tạo giằng hoặc bằng của nó nếu có, nếu không thì {}
áp dụng các bước này theo cách đệ quy).T
là một loại lớp với hàm tạo mặc định do người dùng cung cấp, hàm tạo đó được gọi.T
là một loại lớp với một hàm tạo mặc định được định nghĩa ngầm định hoặc = default
ed, thì đối tượng được khởi tạo bằng 0 và sau đó hàm tạo mặc định được gọi.T
là một std::initializer_list
, giá trị trả về là một danh sách trống như vậy.T
là loại không phải lớp - kiểu trả về không thể là mảng), giá trị trả về là không khởi tạo.{}
, có thể có hoặc không có giá trị init.
Đây là một loại tay ngắn cho một thể hiện mới của kiểu trả về của phương thức.