C ++ 11 قدم منشئين استثنائيين يأخذون `كونست شار *`. لكن لماذا؟ [c++]


Answers

أنا لست متأكدا مما إذا كان السبب، ولكن الشيء الوحيد هو أن runtime_error يضمن أن انها منشئ نسخة لن رمي، مما يدل على نوع من آلية عد إشارة.

يعني منشئ إضافي أنه سيكون لديك فقط لجعل نسخة واحدة، من شار * إلى مشينسم الأساسية، بدلا من مرتين. مرة واحدة في سلسلة ومن ثم في آلية المرجعية

Question

عيب مكتبة القياسية # 254 الذي يغطي إضافة منشئات استثناء جديدة:

std::logic_error::logic_error(const char* what_arg);
std::runtime_error::runtime_error(const char* what_arg);
// etc.

يعطي الأساس المنطقي لفكرة أن تخزين std::string s يفتح بعض علب من الديدان المتعلقة احتمال الذاكرة إشكالية تخصيص.

ومع ذلك، بعد الشروع في مناقشة من قبل أورلب في الصالة ، فإنه يضربني أنه ما لم يكن المعيار لتفويض أن what_arg كانت فقط من أي وقت مضى سلسلة الحرفية (أو مؤشر لبعض المخزن المؤقت أخرى من مدة التخزين الثابتة)، فإنه سيكون لأداء نسخة من سلسلة C على أي حال من أجل الحفاظ على تعريف جيدا وظيفة عضو what() .

ذلك بسبب:

void bar() {
   char buf[] = "lol";
   throw std::runtime_error(buf);
}

void foo() {
   try {
      bar();
   }
   catch (std::exception& e) {
      std::cout << e.what() << '\n';   // e.what() points to destroyed data!
   }
}

ولكنني لا أستطيع أن أرى أي ولاية من هذا القبيل. في الواقع، ما إذا كانت كائنات استثناء نسخة عميقة what_arg أو لا يبدو أن غير محددة تماما.

وإذا ما فعلوا ذلك، يبدو أن جزءا كبيرا من الأساس المنطقي لإضافة العبء الزائد في المقام الأول (إزالة المخصصات الإضافية) يبدو خاليا تماما.

هل هذا من المحتمل أن يكون عيبا معياري، أم أنا في عداد المفقودين شيء هنا؟
هل هذا مجرد حالة من "مبرمج: لا تمرير مؤشرات التعلق في أي مكان"؟




كيف يتعامل ليبك ++ مع هذه المشكلة؟

وهم يستخدمون حاليا سلسلة محسوبة لتخزين الرسالة:

class _LIBCPP_EXCEPTION_ABI logic_error
    : public exception
{
private:
    _VSTD::__libcpp_refstring __imp_;

حيث يتم تهيئة __imp_ كما يلي:

logic_error::logic_error(const string& msg) : __imp_(msg.c_str()) {}

logic_error::logic_error(const char* msg) : __imp_(msg) {}

هذه السلسلة، __libcpp_refstring ، تخصيص مخزن مؤقت جديد عند تخزين جديد char const* :

explicit __libcpp_refstring(const char* msg) {
        std::size_t len = strlen(msg);
        _Rep_base* rep =
             static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1));

ولكن، بالطبع، منشئ نسخة من __libcpp_refstring لا تخصيص مخزن مؤقت جديد.

(نعم، هذا لا يجيب على السؤال، ولكن ينبغي أن يلقي بعض الضوء على هذه المسألة أعتقد، على سبيل المثال، إذا كان هناك فقط std::string const& ستر std::string const& كتور في logic_error ، يجب أن يكون هناك تخصيص إضافي واحد للمرجع -عداد.)