Apa arti pernyataan "return {}" dalam C ++ 11?


115

Apa pernyataan itu

return {};

di C ++ 11 menunjukkan, dan kapan menggunakannya sebagai ganti (katakanlah)

return NULL;

atau

return nullptr;

59
itu mengembalikan turunan bawaan dari tipe kembalian fungsi.
— Richard Hodges

Atau sederhana return;tanpa nilai?
— i486

Tidak, seperti yang diungkapkan diskusi, itu adalah kesalahan waktu kompilasi jika fungsi Anda harus mengembalikan sesuatu (yaitu bukan tipe pengembalian void) dan Anda menulis hanya return; Di sisi lain return{};valid jika Anda memiliki tipe pengembalian.
— Pedia

@Pedia Tidak selalu, beberapa objek akan membutuhkan argumen untuk dibangun
— MM

Jawaban:


108

return {};menunjukkan "mengembalikan objek dari jenis fungsi yang diinisialisasi dengan penginisialisasi daftar kosong ". Perilaku tepatnya bergantung pada tipe objek yang dikembalikan.

Dari cppreference.com (karena OP diberi tag C ++ 11, saya mengecualikan aturan di C ++ 14 dan C ++ 17; lihat tautan untuk detail lebih lanjut):

  • Jika braced-init-list kosong dan T adalah tipe kelas dengan konstruktor default, inisialisasi nilai dilakukan.
  • Sebaliknya, jika T adalah jenis agregat, inisialisasi agregat dilakukan.
  • Sebaliknya, jika T adalah spesialisasi dari std :: initializer_list, objek T akan diinisialisasi langsung atau diinisialisasi salinan, bergantung pada konteksnya, dari braced-init-list.
  • Jika tidak, konstruktor T dianggap, dalam dua tahap:

    • Semua konstruktor yang menggunakan std :: initializer_list sebagai satu-satunya argumen, atau sebagai argumen pertama jika argumen yang tersisa memiliki nilai default, diperiksa, dan dicocokkan dengan resolusi yang berlebihan terhadap argumen tunggal tipe std :: initializer_list
    • Jika tahap sebelumnya tidak menghasilkan kecocokan, semua konstruktor T berpartisipasi dalam resolusi berlebih terhadap kumpulan argumen yang terdiri dari elemen daftar braced-init, dengan batasan bahwa hanya konversi non-penyempitan yang diperbolehkan. Jika tahap ini menghasilkan konstruktor eksplisit sebagai yang paling cocok untuk inisialisasi daftar salinan, kompilasi gagal (catatan, dalam inisialisasi salinan sederhana, konstruktor eksplisit tidak dipertimbangkan sama sekali).
  • Sebaliknya (jika T bukan tipe kelas), jika braced-init-list hanya memiliki satu elemen dan T bukan tipe referensi atau tipe referensi yang kompatibel dengan tipe elemen, T adalah langsung- diinisialisasi (dalam inisialisasi daftar langsung) atau inisialisasi salinan (dalam inisialisasi daftar salinan), kecuali bahwa mempersempit konversi tidak diperbolehkan.

  • Sebaliknya, jika T adalah tipe referensi yang tidak kompatibel dengan tipe elemen. (ini gagal jika referensi adalah referensi nilai l non-const)
  • Sebaliknya, jika braced-init-list tidak memiliki elemen, T akan diinisialisasi nilai.

Sebelum C ++ 11, untuk fungsi yang mengembalikan a std::string, Anda harus menulis:

std::string get_string() {
    return std::string();
}

Menggunakan sintaks brace di C ++ 11, Anda tidak perlu mengulangi tipe:

std::string get_string() {
    return {}; // an empty string is returned
}

return NULLdan return nullptrharus digunakan ketika fungsi mengembalikan tipe penunjuk:

any_type* get_pointer() {
    return nullptr;
}

Namun, NULLtidak digunakan lagi sejak C ++ 11 karena ini hanya alias ke nilai integer (0), sedangkan nullptrtipe pointer sebenarnya:

int get_int() {
    return NULL; // will compile, NULL is an integer
}

int get_int() {
    return nullptr; // error: nullptr is not an integer
}

91

Ini mungkin membingungkan:

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

Ini mungkin bukan:

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

9
Jadi, ini adalah kesalahan waktu kompilasi jika tipe kembalian tidak memiliki konstruktor default, benar?
— Pedia

10
Ini adalah kesalahan kompilasi jika tipe yang dikembalikan adalah kelas yang tidak memiliki konstruktor default non-eksplisit dan bukan agregat.
— Oktalis

3
Jika tipe memiliki initializer_listkonstruktor, bukankah itu akan digunakan jika konstruktor default tidak tersedia?
— celtschk

4
"mungkin membingungkan"? Apakah ini mengapa beberapa jiwa yang tidak disebutkan namanya merujuk pada "Kecabulan yang membengkak itu adalah C ++"? Dapatkah penghematan apa pun dalam penekanan tombol yang diberikan ini mungkin membenarkan potensi kurangnya kejelasan yang ditawarkannya? Ini adalah pertanyaan yang tulus. Tolong yakinkan saya dengan contoh praktis.
— MickeyfAgain_BeforeExitOfSO

4
return {}TIDAK setara denganreturn SomeObjectWithADefaultConstructor{};
— MM

26

return {};berarti itu {}adalah penginisialisasi untuk nilai kembali . Nilai kembali diinisialisasi daftar dengan daftar kosong.


Berikut adalah beberapa latar belakang pada nilai kembalian , berdasarkan [stmt.return] dalam Standar C ++:

Untuk fungsi yang mengembalikan dengan nilai (yaitu tipe yang dikembalikan bukan referensi dan bukan void ), ada objek sementara yang disebut nilai yang dikembalikan . Objek ini dibuat oleh returnpernyataan, dan penginisialisasinya bergantung pada apa yang ada di pernyataan return.

Nilai yang dikembalikan bertahan hingga akhir ekspresi penuh dalam kode yang memanggil fungsi; jika ia memiliki tipe kelas, maka destruktornya akan berjalan kecuali ia memiliki masa pakai diperpanjang oleh pemanggil yang mengikat referensi langsung padanya.

Nilai kembali dapat diinisialisasi dengan dua cara berbeda:


Dengan asumsi Tadalah jenis kembalian fungsi, maka catatan yang return T{};berbeda dengan return {}: di sebelumnya, sementara T{}dibuat, dan kemudian nilai kembalian diinisialisasi salinan dari sementara itu.

Ini akan gagal untuk dikompilasi jika Ttidak memiliki copy / move-constructor yang dapat diakses, tetapi return {};akan berhasil bahkan jika konstruktor tersebut tidak ada. Dengan demikian, return T{};mungkin menunjukkan efek samping dari copy-konstruktor dll, meskipun ini adalah konteks penghapusan salinan jadi mungkin tidak.


Berikut rekap singkat dari daftar-inisialisasi di C ++ 14 (N4140 [dcl.init.list] / 3), di mana penginisialisasi adalah daftar kosong:

  • Jika Tmerupakan agregat, maka setiap anggota diinisialisasi dari brace-or-equal-initializer jika ada, sebaliknya seolah-olah oleh{} (jadi terapkan langkah-langkah ini secara rekursif).
  • Jika T adalah tipe kelas dengan konstruktor default yang disediakan pengguna, konstruktor tersebut akan dipanggil.
  • Jika Tadalah tipe kelas dengan = defaultkonstruktor default yang didefinisikan secara implisit, atau ed default, objek tersebut diinisialisasi nol dan kemudian konstruktor default dipanggil.
  • Jika Tadalahstd::initializer_list , nilai yang dikembalikan adalah daftar kosong tersebut.
  • Jika tidak (yaitu Ttipe non-kelas - tipe kembalian tidak bisa berupa array), nilai kembalian diinisialisasi nol.

Agregat init diutamakan, dan secara rekursif menginisialisasi setiap anggota dengan {}, yang mungkin bernilai atau tidak.
— TC

@TC benar, saya menggunakan cppreference tetapi mengabaikan "hingga C ++ 14"
— MM

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.