std::move
دلالات النقل std::move
std::move لا تنقل شيئًا فعليًا — تحوّل تعبيرًا إلى rvalue reference، ما يخبر المترجم أنه يمكن «سرقة» موارده الداخلية بدل نسخها.
نسخ كائن كبير مثل std::vector أو std::string تقليديًا يعني حجز ذاكرة جديدة ونسخ كل عنصر — مكلف. move semantics (ميزة C++11) تسمح بدل ذلك بـ«سرقة» المؤشرات الداخلية من الكائن المصدر مباشرة وترك المصدر بحالة فارغة صالحة، بلا أي نسخ فعلي للبيانات — عملية بتكلفة ثابتة (O(1)) بدل تكلفة تتناسب مع الحجم.
std::move نفسها لا تنقل شيئًا — هي فقط cast يحوّل lvalue إلى rvalue reference، فيرشد المترجم لاستخدام move constructor أو move assignment operator بدل النسخة العادية إن كانا متوفرين بالنوع.
الصياغة
Type target = std::move(source); void func(Type&& rvalueRef);
📄 مثال
std::vector<int> big = {1, 2, 3, 4, 5};
std::vector<int> target = std::move(big);
// target يملك البيانات الآن، big أصبح فارغًا وصالحًا للاستخدام (لكن حالته غير محددة القيمة)
std::cout << target.size(); // 5
std::cout << big.size(); // 0 عادة، لكن لا تعتمد على القيمة الدقيقةأهم النقاط
| العنصر | الوظيفة |
|---|---|
| std::move(x) | cast يحوّل x إلى rvalue reference — لا ينقل شيئًا بنفسه |
| move constructor | باني يأخذ Type&& ويسرق موارد المصدر بدل نسخها |
| move assignment | عامل = يأخذ Type&& لنفس الغرض عند التعيين |
| rvalue reference (&&) | نوع مرجعي جديد بـ C++11 يشير لقيم مؤقتة يمكن «سرقة» مواردها بأمان |
💡 نصائح عملية
- استخدم std::move عندما تنقل ملكية كائن كبير (vector، string) ولن تحتاج القيمة الأصلية بعدها
- بعد std::move(x)، لا تستخدم x إلا بإعادة تهيئته أولًا — حالته «صالحة لكن غير محددة القيمة»
⚠️ أخطاء شائعة
- استخدام المتغيّر الأصلي بعد std::move عليه وكأن قيمته ما زالت كما كانت — سلوك خاطئ منطقيًا رغم أنه غالبًا لا يُعطّل البرنامج
- تطبيق std::move على قيمة سترجعها الدالة (return std::move(local);) — يمنع تحسين المترجم التلقائي (RVO) وغالبًا يبطّئ الكود
خصائص ذات صلة
🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار CPP الكامل بالعربي.