Di C ++ 11, kita bisa menulis kode ini:
struct Cat {
Cat(){}
};
const Cat cat;
std::move(cat); //this is valid in C++11
ketika saya panggil std::move
, artinya saya ingin memindahkan objek, yaitu saya akan mengubah objek. Untuk memindahkan const
objek tidak masuk akal, jadi mengapa std::move
tidak membatasi perilaku ini? Itu akan menjadi jebakan di masa depan, bukan?
Di sini jebakan berarti seperti yang disebutkan Brandon dalam komentar:
"Saya pikir dia bersungguh-sungguh" menjebak "dia dengan licik karena jika dia tidak menyadarinya, dia berakhir dengan salinan yang bukan itu yang dia inginkan."
Dalam buku 'Effective Modern C ++' karya Scott Meyers, ia memberi contoh:
class Annotation {
public:
explicit Annotation(const std::string text)
: value(std::move(text)) //here we want to call string(string&&),
//but because text is const,
//the return type of std::move(text) is const std::string&&
//so we actually called string(const string&)
//it is a bug which is very hard to find out
private:
std::string value;
};
Jika std::move
dilarang beroperasi pada suatu const
objek, kita bisa dengan mudah mengetahui bugnya, bukan?
std::move
dengan sendirinya tidak melakukan apa pun pada objek. Orang bisa membantah bahwastd::move
nama itu buruk.CAT cat2 = std::move(cat);
, dengan asumsiCAT
mendukung tugas-pindah biasa.std::move
hanya gips, tidak benar-benar menggerakkan apa punJawaban:
di sini kita melihat penggunaan
std::move
on aT const
. Ini mengembalikan aT const&&
. Kami memiliki konstruktor bergerakstrange
yang membutuhkan tipe ini.Dan itu disebut.
Memang benar bahwa jenis aneh ini lebih jarang daripada bug yang akan diperbaiki proposal Anda.
Tapi, di sisi lain, yang sudah ada
std::move
bekerja lebih baik dalam kode generik, di mana Anda tidak tahu apakah tipe yang Anda gunakan adalah aT
atau aT const
.sumber
std::move
suatuconst
objek.const T&&
. Ini mengungkapkan "protokol API" dari jenis "Saya akan mengambil rvalue-ref tapi saya berjanji tidak akan memodifikasinya". Saya kira, selain saat menggunakan mutable, itu tidak biasa. Mungkin kasus penggunaan lain adalah untuk dapat digunakanforward_as_tuple
di hampir semua hal dan kemudian menggunakannya.Ada trik di sini yang Anda abaikan, yaitu
std::move(cat)
tidak benar-benar memindahkan apa pun . Ini hanya memberi tahu kompiler untuk mencoba bergerak. Namun, karena kelas Anda tidak memiliki konstruktor yang menerima aconst CAT&&
, ia akan menggunakanconst CAT&
konstruktor salinan implisit , dan menyalin dengan aman. Tidak ada bahaya, tidak ada jebakan. Jika konstruktor salinan dinonaktifkan karena alasan apa pun, Anda akan mendapatkan kesalahan kompiler.mencetak
COPY
, tidakMOVE
.http://coliru.stacked-crooked.com/a/0dff72133dbf9d1f
Perhatikan bahwa bug dalam kode yang Anda sebutkan adalah masalah kinerja , bukan masalah stabilitas , jadi bug seperti itu tidak akan pernah menyebabkan kerusakan. Ini hanya akan menggunakan salinan yang lebih lambat. Selain itu, bug seperti itu juga terjadi untuk objek non-const yang tidak memiliki konstruktor pemindah, jadi sekadar menambahkan
const
beban berlebih tidak akan menangkap semuanya. Kita bisa memeriksa kemampuan untuk memindahkan konstruksi atau memindahkan assign dari tipe parameter, tapi itu akan mengganggu kode template generik yang seharusnya kembali ke copy konstruktor. Dan sih, mungkin seseorang ingin dapat membangunconst CAT&&
, dari siapa saya mengatakan dia tidak bisa?sumber
const
lvalue juga tidak akan membantu. [class.copy] §8: "Jika tidak, konstruktor salinan yang dideklarasikan secara implisit akan memiliki formulirX::X(X&)
"Salah satu alasan mengapa sisa jawaban sejauh ini terabaikan adalah kemampuan untuk kode generik yang tangguh dalam menghadapi pemindahan. Sebagai contoh katakanlah saya ingin menulis fungsi umum yang memindahkan semua elemen dari satu jenis wadah untuk membuat jenis wadah lain dengan nilai yang sama:
Keren, sekarang saya bisa membuat file
vector<string>
dari adeque<string>
dan setiap individustring
akan dipindahkan dalam prosesnya.Tetapi bagaimana jika saya ingin pindah dari file
map
?Jika
std::move
bersikeras pada non-const
argumen, contoh di atasmove_each
tidak akan dikompilasi karena mencoba untuk memindahkan aconst int
(key_type
darimap
). Tetapi kode ini tidak peduli jika tidak dapat memindahkankey_type
. Ini ingin memindahkanmapped_type
(std::string
) untuk alasan kinerja.Untuk contoh ini, dan banyak contoh lain seperti itu dalam pengkodean generik yang
std::move
merupakan permintaan untuk pindah , bukan permintaan untuk pindah.sumber
Saya memiliki perhatian yang sama dengan OP.
std :: move tidak memindahkan objek, juga tidak menjamin objek dapat dipindahkan. Lalu kenapa disebut move?
Saya pikir menjadi tidak dapat dipindahkan dapat menjadi salah satu dari dua skenario berikut:
1. Jenis yang bergerak adalah const.
Alasan kami memiliki kata kunci const dalam bahasa ini adalah karena kami ingin kompiler mencegah perubahan apa pun pada objek yang didefinisikan menjadi const. Diberikan contoh dalam buku Scott Meyers:
Apa artinya secara harfiah? Pindahkan string const ke value member - setidaknya, itulah pemahaman saya sebelum saya membaca penjelasannya.
Jika bahasa bermaksud untuk tidak melakukan perpindahan atau tidak menjamin perpindahan dapat diterapkan saat std :: move () dipanggil, maka secara harfiah menyesatkan saat menggunakan word move.
Jika bahasa tersebut mendorong orang-orang yang menggunakan std :: move agar memiliki efisiensi yang lebih baik, jebakan seperti ini harus dicegah sedini mungkin, terutama untuk jenis kontradiksi literal yang jelas ini.
Saya setuju bahwa orang harus sadar bahwa memindahkan konstanta tidak mungkin, tetapi kewajiban ini tidak berarti bahwa penyusun dapat diam ketika kontradiksi yang jelas terjadi.
2. Objek tidak memiliki konstruktor bergerak
Secara pribadi, menurut saya ini adalah cerita yang terpisah dari keprihatinan OP, seperti yang dikatakan Chris Drew
sumber
Saya terkejut tidak ada yang menyebutkan aspek kompatibilitas ke belakang ini. Saya percaya,
std::move
sengaja dirancang untuk melakukan ini di C ++ 11. Bayangkan Anda bekerja dengan basis kode lama, yang sangat bergantung pada pustaka C ++ 98, jadi tanpa fallback pada tugas penyalinan, pemindahan akan merusak banyak hal.sumber
Untungnya Anda dapat menggunakan cek clang-tidy untuk menemukan masalah tersebut: https://clang.llvm.org/extra/clang-tidy/checks/performance-move-const-arg.html
sumber