c++ - هل هناك أي سلبيات لوضع علامات على جميع المتغيرات التي لا تعدلها const؟




refactoring (4)

بعد الكثير من googling ، وجدت الكثير حول وظائف الوسم ومعلماتها كـ const ، لكن لا يوجد دليل على تحديد المتغيرات كـ const .

إليك مثال بسيط حقًا:

#include <string>
#include <iostream>

void example(const std::string& x) {
  size_t length = x.length();
  for (size_t i = 0; i < length; ++i) {
    std::cout << x.at(i) << std::endl;
  }
}

int main() {
  example("hello");
}

لماذا لا تصنع

size_t length = x.length();

كون مثل

const size_t length = x.length();

بالإقناع؟

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

على الرغم من هذه الميزة ، لا أرى أنها تستخدم كثيرًا (في أكواد برامج C ++ التي رأيتها) أو ذكرت ما يقرب من قدر عمل الدوال ومعلماتها const .

هل هناك بعض الجوانب السلبية للقيام بذلك بخلاف الحاجة إلى كتابة 5 أحرف إضافية؟ لم أجد الكثير حول هذا الموضوع ، ولا أرغب في إطلاق النار على نفسي إذا كانت هناك مشكلة في وجود عدد كبير من العناصر الثابتة.


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

المشكلة هي أن هذا في الأساس لا يحدث في الواقع.

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

const لا يستحق عن بعد السعر الذي تدفعه مقابله في الغالبية العظمى من المواقف. لا يوجد سوى بضع حالات يحميك فيها const فعليًا (على سبيل المثال ، ضبط المفاتيح) ، ولكن حتى ذلك الحين ، يمكن إثباتها إذا كان عليك أن تكون معتوهًا تمامًا لتجربة ذلك في المقام الأول ، وربما لا تستحق كل قواعد اللغة و ازدواجية رمز التعليمات البرمجية و metalogic زائدة عن الحاجة.

const هي فكرة جميلة قد تكون لطيفة من الناحية النظرية ، ولكن الحقائق العملية هي أن const هو مضيعة كاملة للوقت والمكان. حرقه بالنار.


أستطيع أن أفكر في سلبيين على الأقل:

  • الفعل: المزيد من الكلمات ، المزيد من الرموز للمعالجة ، ...
  • القصور الذاتي: إذا كنت بحاجة إلى تعديله ، فستضطر إلى الانتقال إلى هذا القسم وإزالته

وكلاهما يستحق كل هذا العناء.

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

أنا شخصياً أستخدم لغة تم اختبارها بشكل ثابت ومثبتة بشكل ثابت بحيث يختار المترجم خطأي في أقرب وقت ممكن ؛ التعليق التوضيحي مع const هو إعطاء معلومات للقارئ والمترجم. أنا أحكم عليه يستحق الرموز 6 إضافية.

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


بدلاً من هذا الكود القياسي:

#import <string>
#import <iostream>

void example(const std::string& x) {
  size_t length = x.length();
  for (size_t i = 0; i < length; ++i) {
    std::cout << x.at(i) << std::endl;
  }
}

int main() {
  example("hello");
}

... أكتب هذا:

#include <string>
#include <iostream>
using namespace std;

void example( string const& s )
{
    for( char const ch : s )
    {
        cout << ch << '\n';
    }
}

auto main()
    -> int
{ example( "hello" ); }

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

العيب الرئيسي لاستخدام const بالنسبة لمعظم الأشياء ، هو عندما يتعين عليك أن تتصل بواجهة برمجة تطبيقات C.

ثم يتعين على المرء فقط اتخاذ بعض قرارات الإحساس بالأمعاء حول نسخ البيانات أو الوثوق في الوثائق واستخدام const_cast .

الإضافة 1:
هل لاحظ أن const على نوع الإرجاع يمنع تحريك دلالات. على حد علمي ، لاحظ هذا أولاً من قِبل أندريه ألكساندريسكو في مقاله الخاص بـ Mojo (C ++ 03) في مجلة Dr Dobbs Journal:

" [A] const مؤقت يشبه التناقض ، وهو تناقض في المصطلحات. نظرًا من منظور عملي ، تفرض const النسخ النسخ في الوجهة.

لذلك ، هذا هو مكان واحد حيث لا ينبغي لأحد استخدام const .

آسف أنني نسيت أن أذكر هذا في الأصل ؛ تم تذكيرني بتعليق المستخدم bogdan على إجابة أخرى.

الإضافة 2:
وعلى نفس المنوال (لدعم دلالات الحركة) ، إذا كان آخر شيء تم القيام به باستخدام وسيطة رسمية هو تخزين نسخة في مكان ما ، فبدلاً من المرور بالرجوع إلى const ، قد يكون من الأفضل استخدام وسيطة غير const مرت عليها القيمة ، لأنه يمكن نقلها ببساطة من.

بمعنى ، بدلا من

string stored_value;

void foo( string const& s )
{
    some_action( s );
    stored_value = s;
}

... أو التكرار الأمثل

string stored_value;

void foo( string const& s )
{
    some_action( s );
    stored_value = s;
}

void foo( string&& s )
{
    some_action( s );
    stored_value = move( s );
}

... فكر فقط في الكتابة

string stored_value;

void foo( string s )
{
    some_action( s );
    stored_value = move( s );
}

يمكن أن يكون أقل فعالية في حالة الوسيطة الفعلية للقيمة ، ويتجاهل مزايا const (القيود على ما يمكن أن يفعله الكود) ، وينتهك اصطلاحًا موحدًا باستخدام const حيثما كان ذلك ممكنًا ، لكنه لا يؤدي بشكل سيء في أي موقف (وهذا هو الهدف الرئيسي ، لتجنب ذلك) ورمز أصغر وربما أكثر وضوحا.

ملاحظات :
¹ لا يحتوي المعيار C ++ على توجيه #import . أيضًا ، تلك الرؤوس ، عند تضمينها بشكل صحيح ، ليست مضمونة لتحديد size_t في مساحة الاسم العالمية.


لا توجد سلبيات لتمييز المتغيرات التي لا تقوم بتعديلها.

على الرغم من ذلك ، هناك بعض الجوانب المتقدمة: سيساعدك المحول البرمجي في التشخيص عندما تقوم بتعديل متغير عن غير قصد لا ينبغي لك / لا تقصده وقد يقوم المحول البرمجي (على الرغم من أن اللغة تحتوي على const_cast mutable وهذا أمر نادر الحدوث) بتوليد أفضل الشفرة.

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

لاحظ أن هذا يمتد إلى وظائف الأعضاء كذلك. اجعلها const عندما يمكنك ذلك - فهي تتيح استخدامها في مزيد من السياقات وتساعد المستخدمين على التفكير في الكود ("استدعاء هذه الوظيفة لن يعدل الكائن" هو معلومات قيمة).





const