std::optional
تمثيل غياب القيمة std::optional
std::optional<T> من C++17 يحمل إمّا قيمة من النوع T أو لا شيء، بشكل صريح وآمن — بديل عن مؤشّرات nullptr أو قيم سنتينل (-1) لتمثيل "لا توجد نتيجة".
قبل C++17، تمثيل نتيجة قد لا توجد (بحث فاشل مثلًا) كان يعتمد على حلول معيبة: مؤشّر nullptr (يحتاج تخصيص ذاكرة إضافي)، قيمة سنتينل مثل -1 (تتعارض مع قيم حقيقية محتملة)، أو استثناء (مكلف لحالة متوقّعة وليست خطأ فعلي). optional<T> يحل هذا بحاوية صغيرة تحمل T مباشرة (بلا تخصيص ذاكرة على الكومة) أو تكون فارغة، مع تحقّق واضح عبر has_value أو operator bool.
الصياغة
std::optional<Type> name = value; // أو std::nullopt للحالة الفارغة
if (name.has_value()) { ... }
Type v = name.value_or(defaultValue);📄 مثال
#include <optional>
std::optional<int> findAge(const std::map<std::string, int>& ages,
const std::string& n) {
auto it = ages.find(n);
if (it != ages.end()) return it->second;
return std::nullopt;
}
if (auto age = findAge(ages, "سارة")) {
std::cout << *age;
}
int safe = findAge(ages, "غير موجود").value_or(0);أهم النقاط
| العنصر | الوظيفة |
|---|---|
| has_value() / operator bool | فحص هل يحتوي قيمة قبل الوصول إليها |
| value() | يرجع القيمة أو يرمي std::bad_optional_access لو فارغ |
| value_or(default) | آمن دائمًا — يرجع القيمة أو البديل المحدَّد دون رمي استثناء |
| operator* | وصول مباشر بلا فحص — سلوك غير معرَّف لو استُخدم على optional فارغ |
💡 نصائح عملية
- استخدمه كنوع إرجاع لأي دالة قد تفشل بإيجاد نتيجة بدل مؤشّر أو قيمة سنتينل غامضة
- value_or أأمن دائمًا من value() أو * عندما لا تريد التعامل مع استثناء أو فحص صريح بكل مرة
⚠️ أخطاء شائعة
- استدعاء value() أو * على optional فارغ دون فحص مسبق — استثناء أو سلوك غير معرَّف
- استخدام optional<T*> بدل optional<T> ظنًا أنه ضروري — optional يعمل مباشرة مع القيم دون حاجة لمؤشّر إضافي
خصائص ذات صلة
🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار CPP الكامل بالعربي.