هل هي ممارسة جيدة لتمرير كائن بنيت كمعلمة إلى وظيفة في C ++؟

StackOverflow https://stackoverflow.com/questions/2724708

  •  02-10-2019
  •  | 
  •  

سؤال

جربت مثالًا مباشرًا أدناه:

typedef struct point
{
    int x;
    int y;
} point;

void cp(point p)
{
    cout<<p.x<<endl;
    cout<<p.y<<endl;
}

int main()
{
    point p1;
    p1.x=1;
    p1.y=2;
    cp(p1);
}

النتيجة المطبوعة هي:

1
2

وهو ما كنت أتوقعه. سؤالي هو: هل تحصل المعلمة p على نسخة كاملة من الكائن P1؟ إذا كان الأمر كذلك ، أتساءل عما إذا كانت هذه ممارسة جيدة؟ (افترضت عندما يصبح الحجم كبيرًا في الحجم ، سيؤدي ذلك إلى إنشاء الكثير من النسخ العامة).

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

المحلول

لا حرج في تمرير الهياكل كمعلمات. يتم تمرير كل شيء بالقيمة في C ++ ، لذا يتم بالفعل صنع نسخة كاملة.

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

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

يمكن تعديل مثالك للعمل مع المراجع بهذه الطريقة:

typedef struct point
{
    int x;
    int y;
} point;

void cp(const point& p) // You can know that cp doesn't modify your struct
{
    cout<<p.x<<endl;
    cout<<p.y<<endl;
}

void mod_point(point& p) // You can know that mod_points modifies your struct
{
    p.x += 1;
    p.y += 1;
}

int main()
{
    point p1;
    p1.x=1;
    p1.y=2;
    cp(p1);
    mod_point(p1);
    cp(p1); // will output 2 and 3
}

نصائح أخرى

نعم ، لا حرج في هذا ونعم ، p هي نسخة كاملة من p1. لن أتصل struct مع اثنين ints كبير ، ولكن إذا struct هل تصبح كبيرة وإذا لم تكن بحاجة إلى تغييره في جسم الوظيفة ، يمكنك التفكير في تمريره عن طريق مرجع const:

void cp(const point& p)
{
    // ...
}

قبل أن أقدم إجابة على سؤالك (تجده في نهاية هذا المنشور) ، إليك ملخص موجز للإمكانيات التي لديك لتمرير الحجج إلى وظيفة:


1. الكائنات التي تم إنشاؤها للنسخ (باستيك بفضل القيمة):

void cp(point p);

هذا هو التمرير على أساس. مؤقت point يتم إنشاء الكائن وبناء نسخ من أي شيء point الكائن الذي تنتقل إليه cp. بمجرد أن يترك التنفيذ cp وظيفة ، يتم تدمير الكائن المؤقت.

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


2. الإشارات إلى الكائنات (مرجعية مرجعية):

void cp(point& p);

هذا هو مرجع. يتوفر الكائن الفعلي الذي تم تمريره إلى الوظيفة (وربما يخضع للتعديل) داخل الوظيفة. إذا كنت لا تريد أن تكون الوظيفة قادرة على تغيير الكائن الذي تم تمريره ، فأعلن المعلمة باسم const point&:

void cp(const point& p);

3. مؤشرات للكائنات (مرجعية مرجعية):

void cp(point* p);

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

void cp(const point* p);

أجب على سؤالك:

معلمات المرور بالقيمة ليست سيئة بطبيعتها بأي شكل من الأشكال. بالطبع ، هناك أنواع يكون بناء النسخ باهظة الثمن (مثل الكائنات الكبيرة أو المعقدة) ، أو حيث يكون لها آثار جانبية معينة (على سبيل المثال مع std::auto_ptr). في هذه الحالات ، يجب أن تكون حذراً. خلاف ذلك ، إنها مجرد ميزة أخرى من C ++ لها استخدامات معقولة تمامًا.

void cp(point p){
}

يحصل عليها بالقيمة

void cp(point *p){
}

يحصل عليه بالرجوع إليه

تماما مثل أي متغير بيانات آخر.

في جافا السيناريو مختلف. تمرير الأشياء دائمًا بالرجوع إليها.

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

يمكنك التفكير في تمرير الكائن بالرجوع إليه

void cp(point& p) // p may be altered!

أو كن مرجعا

void cp(const point& p) // p may not be altered!

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

void cp (point & p const) const {

    cout << p.x << endl;
    cout << p.y << endl;

}

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