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;
Pedia
sumber
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
}
rgmt
sumber
91

Ini mungkin membingungkan:

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

Ini mungkin bukan:

SomeObjectWithADefaultConstructor foo()
{
  return {};
  // equivalent to return SomeObjectWithADefaultConstructor {};
}
Richard Hodges
sumber
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.
MM
sumber
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
3

Ini semacam kependekan untuk contoh baru dari tipe kembalian metode.

Victor Mwenda
sumber