سؤال

$ 5.2.11/7 - [ملاحظة: اعتمادًا على نوع الكائن ، عملية كتابة من خلال المؤشر أو LVALUE أو المؤشر إلى عضو البيانات الناتج عن const_cast يلقي بعيدا عن Qualifier68) مايو إنتاج سلوك غير محدد (7.1.5.1). ] "

إن كلمات هذا القسم (C ++ 03) مفاجأة بالنسبة لي. ما هو مفاجئ هما شيئان.

أ) أولاً ، استخدام "مايو". لماذا "قد"؟ الأماكن الأخرى في المعيار محددة للغاية حول السلوك غير المحدد

ب) لماذا هذا الصب بعيدا عن قدة كائن const في الأصل وليس على الفور "سلوك غير محدد". لماذا يجب أن يتم تشغيل الكتابة لكتابة UB؟

هل كانت مفيدة؟

المحلول

أ) أولاً ، استخدام "مايو". لماذا "قد"؟ الأماكن الأخرى في المعيار محددة للغاية حول السلوك غير المحدد

لا تنظر بعمق في استخدام الكلمة مايو هنا. النقطة المهمة هي أن الابتعاد عن القدة في هذه الحالة يسبب سلوكًا غير محدد.

يستخدم معيار C ++ "قد" أو "قد" في كثير من الأحيان ، كما في:

1.3.12: سلوك غير محدد مايو من المتوقع أيضًا أن يغفل هذا المعيار الدولي وصف أي تعريف صريح للسلوك.

التركيز لي. في الأساس ، يستخدم المعيار كلمة "قد" كما في "يسمح ل".

ب) لماذا هذا الصب بعيدا عن قدة كائن const في الأصل وليس على الفور "سلوك غير محدد". لماذا يجب أن يتم تشغيل الكتابة لكتابة UB؟

تؤدي الكتابة إلى UB لأنه من الممكن تخزين كائنات const في ذاكرة القراءة فقط على منصات معينة.

نصائح أخرى

أفهم أنه لن يكون UB إلا إذا كان الكائن المعني هو كائن Const بشكل أساسي بدلاً من مؤشر Const أو إشارة إلى كائن لم يكن في الأصل const.

الفكرة هي أنه يمكن تحميل البيانات بشكل أساسي في جزء من الذاكرة للقراءة فقط ، والكتابة إلى ذلك لن يعمل. ومع ذلك ، من المضمون العمل بشكل صحيح إذا كان الكائن المعني قابل للتغيير بشكل أساسي.

السابق:

const int  x = 4;
const int *y = x;

*const_cast<int*>(x) = 3; // UB - the pointed-to object may 
                          // be in read-only memory or whatever.

int        a = 7;
const int *b = a;

*const_cast<int*>(b) = 6; // Not UB - the pointed-to object is 
                          // fundamentally mutable.

للتعليق أدناه ، لأن الرمز يبدو فظيعًا في التعليقات:

في الفقرة 7.1. 5.1/4 من المعيار ، المثال المقدم هو:

int i = 2;
const int * cip; // pointer to const int
cip = &i;        // OK: cv-qualified access path to unqualified
...
int* ip;
ip = const_cast <int *>( cip ); // cast needed to convert const int* to int*
*ip = 4;                        // defined: *ip points to i, a non-const object

لذلك هذا مسموح به على وجه التحديد.

لسؤالك الأول ، إذا كان هناك شيء ما مايو تنتج سلوكًا غير محدد ، فهذا لا يجعله أقل تفسيرًا.

بالنسبة للجزء الثاني ، أتصور أنه لأسباب قابلية التشغيل البيني. على سبيل المثال ، لا (أو لم يفعل ذلك ، قبل C99) const الكلمة الرئيسية ، لذلك إذا كنت تريد تمرير كائن const إلى وظيفة C ، فيجب أن يتم إبعاد القدة. لذلك يحدد معيار C ++ أن هذا مسموح به طالما لم يتم إجراء أي كتابة. إذا كانت وظيفة C للقراءة فقط ، فيمكن إبعاد القدة بأمان.

حتى في C ++ ، فإن التصحيح غير المتناسق أو غير المكتمل أمر شائع جدًا أيضًا. لذلك ، نواجه من حين لآخر المواقف التي يتعين علينا فيها التخلص من الوفرة من أجل تمرير كائن const إلى وظيفة لا تعدل وسيطتها ، ولكنها تأخذها من قبل غير مؤكد.

أعتقد أن هذا بسبب أ const يمكن تخزين الكائن في ذاكرة القراءة فقط. وبالتالي ، يمكن أن يكون للكتابة إليها العديد من التأثيرات المختلفة: تعطل البرنامج أو خطأ التجزئة أو عدم وجود تأثير.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top