تحويل std::string إلى int: معركة الأداء وسهولة الاستخدام في C++

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: السؤال الأبدي "std::string إلى int"

\n\n

مرحبًا، زميلي المبرمج! إذا سبق لك أن كتبت محللًا للتكوينات بلغة C++، أو عالجت مدخلات المستخدم، أو استخرجت أرقامًا من ملف CSV، فبالتأكيد واجهت المهمة: "كيف نحول سلسلة نصية عادية (std::string) إلى عدد صحيح (int)؟". قد يبدو الأمر بسيطًا، لكن عند النظر في Stack Overflow، سترى آلاف الأصوات وعشرات الإجابات. لماذا؟ لأن خلف هذا السؤال البسيط يكمن عالم كامل من المفاضلات بين سهولة الاستخدام والأمان والأداء.

\n\n

في هذه المقالة، لن نقدم إجابة جافة فحسب. بل سنقيم معركة حقيقية بين الطرق الرئيسية للتحويل: std::stoi و std::from_chars (C++17) و std::stringstream و atoi القديم الجيد، بل وسنكتب حلاً خاصًا بنا. ستعرف أي طريقة تختار لخادم عالي التحميل، وأيها للنماذج الأولية السريعة. هيا بنا!

\n\n

الطريقة 1: الكلاسيكية — std::stoi (C++11)

\n\n

منذ C++11، ظهرت في المكتبة القياسية الدالة الأنيقة std::stoi. إنها بسيطة، قابلة للقراءة، وتلقي استثناءات عند الأخطاء. هذا هو اختيار 90% من المطورين للمهام اليومية.

\n\n
#include <iostream>\n#include <string>\n\nint main() {\n    std::string number_str = "12345";\n    try {\n        int value = std::stoi(number_str);\n        std::cout << "العدد: " << value << std::endl;\n    } catch (const std::invalid_argument& e) {\n        std::cerr << "خطأ: السلسلة لا تحتوي على أرقام!" << std::endl;\n    } catch (const std::out_of_range& e) {\n        std::cerr << "خطأ: العدد خارج نطاق int!" << std::endl;\n    }\n    return 0;\n}
\n\n

إيجابيات وسلبيات std::stoi

\n
    \n
  • الإيجابيات: البساطة، دعم الإعدادات المحلية (يتعرف على الفواصل كفواصل عشرية)، معالجة تلقائية للأخطاء عبر الاستثناءات.
  • \n
  • السلبيات: الاستثناءات مكلفة. إذا كنت تحلل ملايين الأرقام في حلقة، فإن try-catch قد يبطئ الكود بشكل كبير.
  • \n
\n\n

الطريقة 2: أسرع من الريح — std::from_chars (C++17)

\n\n

إذا كنت تكتب تطبيقًا عالي التحميل حيث كل نانوثانية لها أهميتها، فإن std::from_chars هو بطلك. هذه الدالة لا تخصص ذاكرة، ولا تلقي استثناءات، ولا تعتمد على الإعدادات المحلية. إنها ببساطة تحول الأحرف إلى رقم وتعيد مؤشرًا إلى نقطة التوقف.

\n\n
#include <iostream>\n#include <charconv>\n#include <string>\n#include <system_error>\n\nint main() {\n    std::string number_str = "98765";\n    int value = 0;\n    auto [ptr, ec] = std::from_chars(number_str.data(), \n                                      number_str.data() + number_str.size(), \n                                      value);\n    if (ec == std::errc()) {\n        std::cout << "العدد: " << value << std::endl;\n    } else {\n        std::cerr << "خطأ في التحويل!" << std::endl;\n    }\n    return 0;\n}
\n\n

لماذا from_chars هو ملك الأداء؟

\n
    \n
  • بدون تكلفة إضافية: لا استثناءات، لا تخصيصات مخفية.
  • \n
  • التعريب معطل: لا حاجة لإضاعة الوقت في التحقق من الفواصل العشرية.
  • \n
  • إرجاع باقي السلسلة: مثالي لتحليل الأعمدة في CSV.
  • \n
\n

وفقًا لاختبارات الأداء، يمكن أن يكون from_chars أسرع بـ 2-10 مرات من stoi، خاصة على السلاسل القصيرة.

\n\n

الطريقة 3: المدفعية الثقيلة — std::stringstream

\n\n

يستخدم العديد من المبرمجين المبتدئين std::stringstream للتحويل. إنها أداة قوية، لكن لمهمة "سلسلة إلى رقم" فهي مبالغ فيها، مثل دبابة لرحلة إلى المتجر لشراء الخبز.

\n\n
#include <sstream>\n#include <string>\n#                

المدونات

توصيات الكتب