Câu hỏi Câu lệnh “return {}” có nghĩa là gì trong C ++ 11?


Tuyên bố gì

return {};

trong C ++ 11 cho biết, và khi nào sử dụng nó thay vì (nói)

return NULL;

hoặc là

return nullptr;

97
2017-09-14 09:33


gốc


nó trả về một thể hiện mặc định được xây dựng của kiểu trả về của hàm. - Richard Hodges
Hay đơn giản return; không có giá trị? - i486
Không, như các cuộc thảo luận cho thấy, nó là một lỗi thời gian biên dịch nếu chức năng của bạn nên trả lại một cái gì đó (nghĩa là không có loại trả về void) và bạn viết chỉ return;   Mặt khác return{}; là hợp lệ nếu bạn có kiểu trả về. - Pedia
@Pedia Không phải luôn luôn, một số đối tượng sẽ yêu cầu đối số để xây dựng - M.M


Các 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 rỗng -bộ khởi tạo danh sáchHành vi chính xác phụ thuộc vào kiểu của đố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; hãy tham khảo liên kết để biết thêm chi tiết):

  • Nếu braced-init-list rỗng và T là một kiểu lớp với một hàm tạo mặc định, việc khởi tạo giá trị được thực hiện.
  • Nếu không, nếu T là một loại tổng hợp, tổng hợp khởi tạo được thực hiện.
  • Nếu không, nếu T là một chuyên môn của std :: initializer_list, đối tượng T được khởi tạo trực tiếp hoặc sao chép-khởi tạo, tùy thuộc vào ngữ cảnh, từ braced-init-list.
  • Nếu không, các nhà xây dựng của T được xem xét, theo hai giai đoạn:

    • Tất cả các hàm tạo lấy std :: initializer_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 so với một đối số duy nhất của kiểu std :: initializer_list
    • Nếu giai đoạn trước không tạo ra kết quả phù hợp, tất cả các nhà xây dựng T tham gia vào quá trình phân giải quá tải đối với tập hợp các đối số bao gồm các phần tử của danh sách-init-braced, 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 khởi tạo rõ ràng là đối sánh tốt nhất cho việc khởi tạo bản sao-danh sách, việc 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 sẽ không được xem xét).
  • Nếu không (nếu T không phải là kiểu lớp), nếu danh sách-init-braced chỉ có một phần tử và T không phải là một kiểu tham chiếu hoặc là kiểu tham chiếu tương thích với kiểu phần tử, T là trực tiếp- được khởi tạo (trong danh sách khởi tạo trực tiếp) hoặc sao chép-khởi tạo (trong bản sao-danh sách khởi tạo), ngoại trừ việc thu hẹp chuyển đổi không được phép.

  • Nếu không, nếu T là kiểu 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 không phải lvalue)
  • Nếu không, nếu braced-init-list không có phần tử, T là giá trị được khởi tạo.

Trước C ++ 11, cho một hàm trả về std::string, bạn đã 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 phải 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ề kiểu con trỏ:

any_type* get_pointer() {
    return nullptr;
}

Tuy nhiên, NULL không được chấp nhận vì C ++ 11 vì nó chỉ là một bí danh cho một giá trị số 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
}

95
2017-09-14 09:40





Điều này có thể gây nhầm lẫn:

int foo()
{
  return {};   // honestly, just return 0 - it's clearer
}

Điều này có lẽ không phải:

SomeObjectWithADefaultConstructor foo()
{
  return {};
  // equivalent to return SomeObjectWithADefaultConstructor {};
}

87
2017-09-14 09:37



Vì vậy, nó là một lỗi thời gian biên dịch nếu kiểu trả về không có một hàm tạo mặc định, đúng không? - Pedia
Đó là lỗi biên dịch nếu kiểu trả về là một lớp không có không rõ ràng constructor mặc định và không phải là tổng hợp. - Oktalist
Nếu loại có initializer_list constructor, sẽ không được sử dụng nếu không có constructor mặc định có sẵn? - celtschk
"có thể gây nhầm lẫn"? Đây có phải là lý do tại sao một số linh hồn vô danh được gọi là "khiêu dâm cồng kềnh đó là C + +"? Bất cứ điều gì có thể tiết kiệm trong tổ hợp phím này cung cấp có thể biện minh cho tiềm năng thiếu sự rõ ràng nó cung cấp? Đây là một câu hỏi chân thành. Hãy thuyết phục tôi với những ví dụ thực tế. - mickeyf
return {}KHÔNG tương đương với return SomeObjectWithADefaultConstructor{}; - M.M


return {}; có nghĩa là {} là bộ khởi tạo cho giá trị trả về. Giá trị trả về là danh sách được khởi tạo 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 hàm trả về theo giá trị (nghĩa là loại trả về không phải là tham chiếu chứ không phải 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 tuyên bố, và initializers của nó phụ thuộc vào những gì đã được trong báo cáo trở lại.

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ó vòng đời mở rộng 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:


Giả định T là kiểu trả về của hàm, sau đó lưu ý rằng 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 nếu T không có bản sao / di chuyển-khởi tạo có thể truy cập, nhưng return {}; sẽ thành công ngay cả khi các nhà xây dựng đó không có mặt. Theo đó, return T{}; có thể hiển thị các tác dụng phụ của tác nhân sao chép, v.v., mặc dù đây là ngữ cảnh sao chép bản sao để nó có thể không.


Đây là tóm tắt ngắn gọn về danh sách khởi tạo trong C ++ 14 (N4140 [dcl.init.list] / 3), trong đó trình khởi tạo là một danh sách trống:

  • Nếu T là tổng hợp, sau đó mỗi thành viên được khởi tạo từ bộ khởi tạo dấu ngoặc đơn hoặc bằng nhau nếu nó có, nếu không bằng {}  (vì vậy hãy áp dụng các bước này một cách đệ quy).
  • Nếu T là một kiểu lớp với một hàm tạo mặc định do người dùng cung cấp, hàm tạo đó được gọi.
  • Nếu T là loại lớp có định nghĩa ngầm hoặc = defaulted constructor mặc định, đối tượng là không được khởi tạo và sau đó hàm tạo mặc định được gọi.
  • Nếu T là một std::initializer_list, giá trị trả lại là một danh sách trống.
  • Nếu không (tức là T là kiểu không phải kiểu lớp - các kiểu trả về không thể là các mảng), giá trị trả về là zero-initialized.

24
2017-09-14 22:43



Tổng hợp init đến trước, và nó đệ quy khởi tạo mọi thành viên với {}, có thể hoặc không thể là giá trị-init. - T.C.
@ T.C. đúng, tôi đã đi bằng cppreference nhưng bỏ qua một "cho đến khi C + + 14" - M.M


Đó là một loại ngắn tay cho một thể hiện mới của phương thức trả về kiểu.


3
2017-09-21 06:23