Saya seorang programmer sederhana. Variabel anggota kelas saya paling sering terdiri dari tipe POD dan kontainer STL. Karena itu saya jarang harus menulis operator penugasan atau menyalin konstruktor, karena ini diterapkan secara default.
Tambahkan ke ini, jika saya menggunakan std::move
pada objek yang tidak dapat dipindahkan, ini menggunakan operator penugasan, artinya std::move
sangat aman.
Karena saya pemrogram sederhana, saya ingin memanfaatkan kapabilitas pemindahan tanpa menambahkan operator konstruktor / penugasan pemindahan ke setiap kelas yang saya tulis, karena kompiler dapat dengan mudah menerapkannya sebagai " this->member1_ = std::move(other.member1_);...
"
Tetapi tidak (setidaknya tidak dalam Visual 2010), apakah ada alasan khusus untuk ini?
Lebih penting; apakah ada cara untuk mengatasi ini?
Pembaruan: Jika Anda melihat jawaban GManNickG, dia memberikan makro yang bagus untuk ini. Dan jika Anda tidak tahu, jika Anda menerapkan semantik bergerak, Anda dapat menghapus fungsi anggota swap.
sumber
MyClass::MyClass(Myclass &&) = default;
?Jawaban:
Generasi implisit dari konstruktor pemindahan dan operator penugasan telah diperdebatkan dan ada revisi besar dalam draf terbaru dari Standar C ++, jadi kompiler yang tersedia saat ini kemungkinan besar akan berperilaku berbeda sehubungan dengan pembuatan implisit.
Untuk informasi lebih lanjut tentang riwayat masalah, lihat daftar makalah WG21 2010 dan cari "mov"
Spesifikasi saat ini (N3225, dari November) menyatakan (N3225 12,8 / 8):
Ada bahasa serupa di 12.8 / 22 yang menentukan kapan operator penugasan pindah secara implisit dideklarasikan sebagai default. Anda dapat menemukan daftar lengkap perubahan yang dibuat untuk mendukung spesifikasi generasi pemindahan implisit saat ini di N3203: Memperketat kondisi untuk menghasilkan gerakan implisit , yang sebagian besar didasarkan pada salah satu resolusi yang diusulkan oleh makalah Bjarne Stroustrup N3201: Bergerak bersama .
sumber
cannot be defaulted *in the class body*
. Jadi, saya mendefinisikan destruktor di luar dan berhasil :). Tapi menurutku agak aneh. Apakah ada yang punya penjelasan? Kompilernya adalah gcc 4.6.1virtual ~D() = default;
seharusnya berfungsi dan masih mengizinkan konstruktor pemindahan implisit.Konstruktor pemindahan yang dihasilkan secara implisit telah dipertimbangkan untuk standar, tetapi bisa berbahaya. Lihat analisis Dave Abrahams .
Pada akhirnya, bagaimanapun, standar tersebut memang memasukkan generasi implisit dari konstruktor pemindahan dan operator penugasan pindahan, meskipun dengan daftar batasan yang cukup substansial:
Namun, bukan itu saja ceritanya. Sebuah ctor dapat dideklarasikan, tetapi tetap didefinisikan sebagai dihapus:
sumber
Tweak2
. Saya kira itu ada hubungannya dengan fakta bahwaNumber
akan dipindahkan danvector
akan disalin ... tapi saya tidak yakin: / Saya mengerti masalahnya akan menurunTweak3
.Ya, saya pergi ke rute itu juga. Berikut makro Anda:
// detail/move_default.hpp #ifndef UTILITY_DETAIL_MOVE_DEFAULT_HPP #define UTILITY_DETAIL_MOVE_DEFAULT_HPP #include <boost/preprocessor.hpp> #define UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR_BASE(pR, pData, pBase) pBase(std::move(pOther)) #define UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT_BASE(pR, pData, pBase) pBase::operator=(std::move(pOther)); #define UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR(pR, pData, pMember) pMember(std::move(pOther.pMember)) #define UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT(pR, pData, pMember) pMember = std::move(pOther.pMember); #define UTILITY_MOVE_DEFAULT_DETAIL(pT, pBases, pMembers) \ pT(pT&& pOther) : \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \ UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR_BASE, BOOST_PP_EMPTY, pBases)) \ , \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \ UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR, BOOST_PP_EMPTY, pMembers)) \ {} \ \ pT& operator=(pT&& pOther) \ { \ BOOST_PP_SEQ_FOR_EACH(UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT_BASE, BOOST_PP_EMPTY, pBases) \ BOOST_PP_SEQ_FOR_EACH(UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT, BOOST_PP_EMPTY, pMembers) \ \ return *this; \ } #define UTILITY_MOVE_DEFAULT_BASES_DETAIL(pT, pBases) \ pT(pT&& pOther) : \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \ UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR_BASE, BOOST_PP_EMPTY, pBases)) \ {} \ \ pT& operator=(pT&& pOther) \ { \ BOOST_PP_SEQ_FOR_EACH(UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT_BASE, BOOST_PP_EMPTY, pBases) \ \ return *this; \ } #define UTILITY_MOVE_DEFAULT_MEMBERS_DETAIL(pT, pMembers) \ pT(pT&& pOther) : \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \ UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR, BOOST_PP_EMPTY, pMembers)) \ {} \ \ pT& operator=(pT&& pOther) \ { \ BOOST_PP_SEQ_FOR_EACH(UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT, BOOST_PP_EMPTY, pMembers) \ \ return *this; \ } #endif
</s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> </s> orang </s>
// move_default.hpp #ifndef UTILITY_MOVE_DEFAULT_HPP #define UTILITY_MOVE_DEFAULT_HPP #include "utility/detail/move_default.hpp" // move bases and members #define UTILITY_MOVE_DEFAULT(pT, pBases, pMembers) UTILITY_MOVE_DEFAULT_DETAIL(pT, pBases, pMembers) // base only version #define UTILITY_MOVE_DEFAULT_BASES(pT, pBases) UTILITY_MOVE_DEFAULT_BASES_DETAIL(pT, pBases) // member only version #define UTILITY_MOVE_DEFAULT_MEMBERS(pT, pMembers) UTILITY_MOVE_DEFAULT_MEMBERS_DETAIL(pT, pMembers) #endif
(Saya telah menghapus komentar sebenarnya, yang panjang dan dokumenter.)
Anda menentukan basis dan / atau anggota di kelas Anda sebagai daftar praprosesor, misalnya:
#include "move_default.hpp" struct foo { UTILITY_MOVE_DEFAULT_MEMBERS(foo, (x)(str)); int x; std::string str; }; struct bar : foo, baz { UTILITY_MOVE_DEFAULT_BASES(bar, (foo)(baz)); }; struct baz : bar { UTILITY_MOVE_DEFAULT(baz, (bar), (ptr)); void* ptr; };
Dan keluarlah seorang konstruktor bergerak dan operator tugas bergerak.
(Sebagai tambahan, jika ada yang tahu bagaimana saya bisa menggabungkan detail ke dalam satu makro, itu akan menjadi besar.)
sumber
VS2010 tidak melakukannya karena mereka bukan Standar pada saat implementasi.
sumber