Жылдыруу семантикасы: терең кароо
Ресурстарды көчүрбөстөн уурдоо - жана муну коопсуз жасоо
std::move аркылуу ачык кастинг жасалганда, компилятор кымбат көчүрүүнүн ордуна арзан жылдыруу жолун тандай алат. Туура колдонулса, жылдыруу семантикасы O(n) терең көчүрүүлөрдү O(1) көрсөткүч алмашууга айлантат - чакырган код өзгөрбөйт.
- маани категорияларын окуп,
T&&rvalue-шилтемеси качан байланарын так билесиз; - туура жылдыруу конструкторун жана жылдыруу менчиктөө операторун жаза аласыз;
- аларды
noexceptдеп белгилөө программанын убадасын гана эмес, өндүрүмдүүлүгүн да өзгөртөрүн түшүндүрө аласыз; - беш эреже колдоно аласыз (жана нөл эрежесин артык көрөсүз);
- аныкталбаган жүрүм-турумга алып келбестен жылдырылгандан кийинки абал тууралуу ой жүгүртө аласыз.
1. Маани категориялары жана rvalue-шилтемелер
C++ тилиндеги ар бир туюнтманын түрү да, маани категориясы да бар. Практикалык жылдыруу семантикасы үчүн негизги бөлүнүү lvalue - аты жана & аркылуу алса боло турган туруктуу дареги бар нерселер - жана rvalue - убактылуу жана башка объекттер, алардын ресурстарын коопсуз алса болот, себеби аларды эч ким кайра көрбөйт - ортосунда.
rvalue-шилтеме, T&& деп жазылат, ал бир гана rvalue менен байланышат. Бүт амал ушунда: T&& параметри бар ашыкча жүктөө так убакыты бүткөн маани аргумент болгондо тандалат, ошондуктан ошол ашыкча жүктөөнүн ичинде аны уурдоо коопсуз.
void f(const std::string& s); // lvalue ашыкча жүктөө: баарын алат, уурдоого болбойт
void f(std::string&& s); // rvalue ашыкча жүктөө: убактылууну алат, уурдаса болот
std::string name = "Ada";
f(name); // f(const std::string&) чакырат - name бул lvalue
f("Ada"); // f(std::string&&) чакырат - убактылуу бул rvalue
f(std::move(name)); // f(std::string&&) чакырат - name кайра керек эмес деп УБАДА беребиз
std::move эч нерсени жылдырбайт. Бул кастинг: ал өз аргументине rvalue-шилтеме чыгарат, ошентип жылдыруу ашыкча жүктөөсү тандалат. Иштин өзү тандалган жылдыруу конструкторунда же жылдыруу менчиктөөдө болот. std::move дегенди "муну убакыты бүтүп жаткандай кара" деп ойлоңуз - жылдырууну кастинг эмес, түрдүн өзү аткарат.
void g(std::string&& s) ичинде s параметринин аты бар, ошондуктан андан жылдыруу үчүн кайрадан std::move(s) жазуу керек. Муну унутсаңыз, унчукпай көчүрүү болуп калат.