سؤال

أعلم أن هناك سؤالات قليلة حول الصواب من الصواب حيث ذكر أن إعلان وظيفة وتعريفه لا يحتاج إلى الاتفاق على معلمات القيمة. وذلك لأن استمرار معلمة القيمة يهم فقط داخل الوظيفة. هذا جيد:

// header
int func(int i);

// cpp
int func(const int i) {
    return i;
}

هل تفعل هذه حقا أفضل الممارسات؟ لأنني لم أر أي شخص يفعل ذلك. لقد رأيت هذا الاقتباس (غير متأكد من المصدر) في أماكن أخرى تمت مناقشة هذا:

"في الواقع، إلى المحول البرمجي، فإن توقيع الوظيفة هو نفسه ما إذا كنت تتضمن هذا Constand أمام معلمة القيمة أم لا."

"تجنب المعلمات Const Pass-Value في تصريحات الوظائف. لا تزال تجعل المعلمة CONST في نفس تعريف الوظيفة إذا لم يتم تعديلها".

تقول الفقرة الثانية عدم وضع CONS في الإعلان. أفترض أن ذلك لأن استنزاز معلمة القيمة لا معنى له كجزء من تعريف الواجهة. إنه تفاصيل التنفيذ.

بناء على هذه التوصية، هل يوصى أيضا بقيم المؤشر لمعلمات المؤشر؟ (لا معنى له في معلمة مرجعية لأنك لا تستطيع إعادة تعيين مرجع.)

// header
int func1(int* i);
int func2(int* i);

// cpp
int func1(int* i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compiles without error

    return *i;
}
int func2(int* const i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compile error

    return *i;
}

ملخص: جعل معلمات القيمة مفيدة لالتقاط بعض أخطاء المنطق. هل هي أفضل الممارسات؟ هل تذهب إلى أقصى حد من مغادرة CONT خارج ملف الرأس؟ هل هو مفيد فقط للقيم المؤشر؟ لما و لما لا؟

بعض المراجع:

C ++ CONST الكلمات الرئيسية - استخدم بحريا؟ استخدام "CONS" لمعلمات الوظائف

مثال عند وجود معلمات القيمة CONTER مفيدة:

bool are_ints_equal(const int i, const int j) {
    if (i = j) { // without the consts this would compile without error
        return true;
    } else {
        return false;
    }
    // return i = j; // I know it can be shortened
}
هل كانت مفيدة؟

المحلول

بلدي تأخذ على ذلك:

إنها ليست فكرة سيئة، لكن القضية بسيطة وأن طاقتك قد تنفق بشكل أفضل على أشياء أخرى.

في سؤالك، قدمت مثالا جيدا على متى قد يصطاد خطأ، ولكن في بعض الأحيان ينتهي بك الأمر في فعل شيء مثل هذا:

void foo(const int count ...)
{
   int temp = count;  // can't modify count, so we need a copy of it
   ++temp;

   /* ... */
}

إيجابيات وسلبيات صغيرة في كلتا الحالتين.

نصائح أخرى

لقد قرأت عدة مرات أن صنع معلمات القيمة في وظيفة const هو شيء سيء القيام به لأنه غير ضروري.

ومع ذلك، أجد أنه من حين لآخر مفيدة لي كتحقق من أن تطبيقي لا يفعل شيئا لا أقتب عنه (كما هو الحال في المثال في نهاية سؤالك).

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

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

لذلك وظيفة Fillarray مع توقيع مثل هذا:

size_t fillArray( data_t* pStart, data_t* const pEnd);

سوف يمنعني من زيادة عن طريق الخطأ pEnd عندما أقصد حقا زيادة pStart. وبعد إنه ليس شيئا كبيرا، لكنني متأكد من أن كل من قام برمجته بأي فترة من الزمن في C. وقد دخل هذا الخطأ.

لسوء الحظ، بعض المترجمين (أنا أتطلع إليك، Sun CC!) تميز بشكل غير صحيح بين الحجج المعلنة CONST وتلك التي لم يتم الإعلان عنها، ويمكنك الحصول على أخطاء حول وظائف غير محددة.

أعتقد أن هذا يعتمد على أسلوبك الشخصي.

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

أحد الأسباب التي قد لا أقوم بها هي أن NONST-NESS من المعلمة القيمة هو تفاصيل تنفيذ أن عملائك لا يحتاجون إلى معرفتهم. إذا قمت لاحقا (عمدا)، قم بتغيير وظيفتك حتى يقوم بالفعل بتغيير هذه القيمة، فستحتاج إلى تغيير توقيع وظيفتك، مما سيجبر عملائك على إعادة ترجمة.

هذا مشابه لماذا يوصي بعض الأشخاص بعدم وجود أساليب افتراضية عامة (المهام الظاهرية - NESS هي تفاصيل تنفيذ يجب إخفتها عن العملاء)، لكنني لست في هذا المعسكر بالذات.

إذا كان هناك كونت كونست كلمة رئيسية؛ يعني أنه لا يمكن تعديل قيمة "أنا" (وهو نوع const). إذا تم تغيير قيمة "I" داخل FOO Destace Compiler ستخبط الخطأ: "

لا يمكن تعديل كائن const

ولكن تغيير "* أنا" (أي * I = 3؛) يعني أنك لا تتغير قيمة "أنا" ولكن قيمة العنوان المدببة ب "أنا"

في الواقع، فإن وظيفة CONST مناسبة للأشياء الكبيرة التي لا ينبغي تغييرها حسب الوظيفة.

يجب علينا جميعا عدم فك كود C ++ لشخص آخر من وقت لآخر. وهذا رمز شخص آخر C ++ هو فوضى كاملة بحكم التعريف: د.

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

لذلك أنا أقدر حقا عندما يكون شخص آخر ثابت في كل مكان (بما في ذلك معلمات القيمة): D

أحب صحة المواقف مثل هذا:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}

هذا يتيح لي استخدام b دون خوف من تعديلها، ولكن ليس علي أن أدفع تكلفة منشئ نسخة.

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