هل استخدام const_cast للوصول إلى القراءة فقط إلى كائن const مسموح به؟
-
20-09-2019 - |
سؤال
في C ++ ، لدي وظيفة لا تتطلب سوى الوصول للقراءة فقط إلى صفيف ولكن يتم إعلانها عن طريق الخطأ على أنها تلقي مؤشر غير مؤشر:
size_t countZeroes( int* array, size_t count )
{
size_t result = 0;
for( size_t i = 0; i < count; i++ ) {
if( array[i] == 0 ) {
++result;
}
}
return result;
}
وأحتاج إلى تسميتها لمجموعة كونستور:
static const int Array[] = { 10, 20, 0, 2};
countZeroes( const_cast<int*>( Array ), sizeof( Array ) / sizeof( Array[0] ) );
هل سيكون هذا سلوكًا غير محدد؟ إذا كان الأمر كذلك - متى سيواجه البرنامج UB - عند القيام بـ const_cast والاتصال بـ functon أو عند الوصول إلى الصفيف؟
المحلول
نعم ، يُسمح بذلك (إذا كان خطيرًا!). إنها الكتابة الفعلية إلى const
الكائن الذي يتحمل السلوك غير المحدد ، وليس يلقي نفسه (7.1.5.1/4 [dcl.type.cv]).
كما الملاحظات القياسية في 5.2.11/7 [expr.const.cast] ، اعتمادا على نوع الكائن محاولة الكتابة من خلال مؤشر هو نتيجة الابتعاد const
قد تنتج سلوك غير محدد.
نصائح أخرى
نظرًا لأن الرمز الخاص بك لا يعدل المصفوفة ، وأخبرت المترجم أنك تعرف ما تفعله باستخدام const_cast
, ، سوف تكون على ما يرام في الواقع. ومع ذلك ، أعتقد أنك تستدعي سلوكًا غير محدد تقنيًا. من الأفضل الحصول على إعلان الوظيفة ثابتًا أو الكتابة أو الإعلان واستخدام الإصدار الآمن منه.
نعم يمكنك ان تفعل. لا ، إنه ليس سلوكًا غير محدد طالما أن الوظيفة حقًا لا تحاول الكتابة إلى الصفيف.
مشكلة const_cast
هو نفسه دائمًا - يتيح لك "كسر القواعد" ، تمامًا مثل الصب من وإلى void*
- بالتأكيد يمكنك القيام بذلك ، ولكن السؤال هو لماذا يجب عليك؟
في هذه الحالة ، لا بأس بالطبع ، لكن يجب أن تسأل نفسك لماذا لم تعلن size_t countZeroes( const int* array, size_t count )
في المقام الأول؟
وكقاعدة عامة حول const_cast
:
- قد ينتج جاهدة للعثور على الأخطاء
- أنت ترفع الوفرة مع المترجم
- في الأساس ، تقوم بتحويل اللغة إلى مستوى أقل.
استخدام const_cast
على كائن يتم تعريفه في البداية على أنه const
هو UB ، وبالتالي فإن السلوك غير المحدد يأتي مباشرة عند النقطة التي تتصل بها const_cast
.