Apa yang bisa saya lakukan dengan objek yang dipindahkan?

138

Apakah standar menentukan dengan tepat apa yang dapat saya lakukan dengan suatu objek setelah dipindahkan? Saya dulu berpikir bahwa semua yang dapat Anda lakukan dengan objek yang dipindahkan adalah melakukan perusakan, tetapi itu tidak akan cukup.

Misalnya, ambil templat fungsi swapseperti yang didefinisikan di pustaka standar:

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

Jelas, harus mungkin untuk menetapkan objek-objek yang dipindahkan, jika tidak, baris 2 dan 3 akan gagal. Jadi apa lagi yang bisa saya lakukan dengan objek yang dipindahkan? Di mana tepatnya saya dapat menemukan detail ini dalam standar?

(Ngomong-ngomong, mengapa T c = std::move(a);bukannya T c(std::move(a));di baris 1?)

fredoverflow
sumber

Jawaban:

53

Objek Pindah-dari ada dalam kondisi yang tidak ditentukan, tetapi valid. Itu menunjukkan bahwa sementara objek mungkin tidak mampu melakukan banyak lagi, semua fungsi anggotanya masih harus menunjukkan perilaku yang ditetapkan - termasuk operator=- dan semua anggotanya dalam keadaan yang ditentukan - dan itu masih membutuhkan penghancuran. Standar tidak memberikan definisi spesifik karena akan unik untuk setiap UDT, tetapi Anda mungkin dapat menemukan spesifikasi untuk tipe Standar. Beberapa kontainer sejenis relatif jelas - mereka hanya memindahkan isinya dan sebuah wadah kosong adalah kondisi valid yang terdefinisi dengan baik. Primitif tidak mengubah objek yang dipindahkan dari.

Catatan: Saya percaya T c = std::move(a)bahwa jika constructor bergerak (atau menyalin konstruktor jika tidak ada gerakan disediakan) secara eksplisit fungsi akan gagal.

Anak anjing
sumber
26
Tidak semua fungsi anggotanya akan menunjukkan perilaku yang ditentukan. Hanya mereka yang tidak memiliki prasyarat. Misalnya, Anda mungkin tidak ingin pop_backpindah-dari vector. Tapi Anda tentu bisa mengetahuinya empty().
Howard Hinnant
6
@Howard Hinnant: pop_backdari yang kosong vectormemiliki perilaku yang tidak terdefinisi, dari memori, jadi saya cukup yakin bahwa pop_backdari vektor yang dipindahkan yang menunjukkan perilaku tidak terdefinisi adalah konsisten.
Puppy
12
Kami sedang mendiskusikan objek yang dipindahkan dari objek. Bukan benda yang diketahui berada dalam keadaan kosong. Objek Pindah-dari memiliki keadaan yang tidak ditentukan (kecuali tentu saja ditentukan lain). [lib.types.movedfrom]
Howard Hinnant
5
@ Howard Tidak ditentukan, tetapi valid, jadi pop_backmasih berperilaku seperti pada vektor yang valid (bahkan mungkin menjadi vektor kosong).
Christian Rau
1
apa arti tidak ditentukan dan valid dalam konteks ini?
Ankur S
114

17.6.5.15 [lib.types.movedfrom]

Objek tipe yang didefinisikan dalam pustaka standar C ++ dapat dipindahkan dari (12.8). Operasi pemindahan dapat secara eksplisit ditentukan atau secara implisit dihasilkan. Kecuali ditentukan lain, objek yang dipindahkan tersebut harus ditempatkan dalam keadaan valid tetapi tidak ditentukan.

Ketika suatu objek dalam keadaan yang tidak ditentukan, Anda dapat melakukan operasi apa pun pada objek yang tidak memiliki prasyarat. Jika ada operasi dengan prasyarat yang ingin Anda lakukan, Anda tidak bisa langsung melakukan operasi itu karena Anda tidak tahu apakah keadaan objek yang tidak ditentukan memenuhi persyaratan.

Contoh operasi yang umumnya tidak memiliki prasyarat:

  • penghancuran
  • tugas
  • pengamat const seperti get, empty,size

Contoh operasi yang umumnya memiliki prasyarat:

  • dereference
  • pop_back

Jawaban ini sekarang muncul dalam format video di sini: http://www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s

Howard Hinnant
sumber
1
Tapi saya bisa memeriksa prasyarat seperti dengan benda lain, kan?
fredoverflow
6
@ FredOverflow Selama pemeriksaan ini sendiri tidak memiliki prasyarat, tentu saja.
Christian Rau
1
@ Chris: Tapi bagaimana itu berbeda dari objek yang normal, tidak pindah-dari?
fredoverflow
2
Mungkin harus menjadi pertanyaan terpisah, tetapi apakah itu berarti: jika saya memiliki string dengan char* buffer;dan int length;anggota, maka konstruktor / tugas saya harus menukar (atau menetapkan) nilai keduanya? Atau akan baik-baik saja, jika panjangnya tidak ditentukan (artinya emptydan sizemengembalikan nilai yang tidak berarti)?
UncleBens
3
@ 6502: Kamu tidak masuk akal. Kelas C ++ 03 tidak "melanggar standar C ++ 0x" karena sebuah ctor jika dihasilkan akan melanggar standar. Dan kode C ++ 03 tidak akan memindahkan kelas itu sehingga tidak ada alasan untuk memindahkan ctor.
MSalters