لماذا هذا التحذير من برنامج التحويل البرمجي IBM XL C/C ++؟

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

  •  06-07-2019
  •  | 
  •  

سؤال

إليك مثال رمز أدنى يوضح المشكلة:

#include <iostream>

class Thing
{
   // Non-copyable
   Thing(const Thing&);
   Thing& operator=(const Thing&);

   int n_;

public:
   Thing(int n) : n_(n) {}

   int getValue() const { return n_;}
};

void show(const Thing& t)
{
   std::cout << t.getValue() << std::endl;
}

int main()
{
   show(3);
}

هذا يعطي نفس الخطأ:

int main()
{
    show( Thing(3) );
}

ينبع برمجي IBM XL C/C ++ 8.0 تحت AIX هذه التحذيرات:

"testWarning.cpp", line 24.9: 1540-0306 (W) The "private" copy constructor "Thing(const Thing &)" cannot be accessed.
"testWarning.cpp", line 24.9: 1540-0308 (I) The semantics specify that a temporary object must be constructed.
"testWarning.cpp", line 24.9: 1540-0309 (I) The temporary is not constructed, but the copy constructor must be accessible.

لقد جربت أيضًا G ++ 4.1.2 مع "-wall" و "-pedantic" ولم أحصل على تشخيص. لماذا الوصول إلى مُنشئ النسخ مطلوب هنا؟ كيف يمكنني القضاء على التحذير ، إلى جانب جعل الكائن قابل للنسخ (الذي هو خارج عن سيطرتي) أو إنشاء نسخة صريحة لتمريرها (عندما يكون كائن الحياة الواقعية مكلفًا للنسخ)؟

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

المحلول

القواعد لهذا في الفقرة 8.5.3/5 من المعيار. هناك ثلاث حالات أساسية تم تحديدها. الأول ينطوي على التهيئة ("3" في حالتك) إما lvalue ، أو وجود نوع فئة. نظرًا لأن أيا من هذه الأشياء غير صحيح ، فإن ما لديك هو الحالة الثالثة: تهيئة مرجع const مع rvalue التي لا تحتوي على نوع فئة. هذه الحالة مغطاة بالرصاصة النهائية في 8.5.3/5:

بخلاف ذلك ، يتم إنشاء وتهيئة مؤقت من النوع "CV1 T1" من تعبير التهيئة باستخدام قواعد تهيئة نسخة غير مرجعية (8.5). ثم يرتبط المرجع إلى المؤقتة. إذا كان T1 مرتبطًا بـ T2 ، فيجب أن يكون CV1 هو نفس التأهيل السيرة خلاف ذلك ، فإن البرنامج غير متشابه.

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

t x = a ؛

هذا يعادل بشكل أساسي:

t x = t (a) ؛

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

T temp1(3);
T temp2(temp1); // requires copy ctor
show(temp2);    // show's reference parameter binds directly to temp2

نصائح أخرى

يسمح C ++ بمجموعتي الأداء الكافي لتجنب نسخ الأشياء المؤقتة ، وانتهاك واحد كما لو القاعدة التي يسمح بها المعيار. لست على دراية بمترجم IBM's Aix C ++ ، لكن يبدو أنه يعتقد show(3) يتطلب المكالمة أن يتم نسخ شيء مؤقت. في هذه الحالة ، يتطلب C ++ أن يكون لديك منشئ نسخ يمكن الوصول إليه على الرغم من أن المترجم الخاص بك ذكي بما يكفي لتجنب استخدامه.

ولكن لماذا show(3) تتطلب نسخة في المقام الأول؟ لا يمكنني معرفة ذلك. مع الحظ ، سيكون Litb على طول قليلا.

شعوري الغريزي هو أن جيري إجابه صحيح ، ولكن لا تزال هناك بعض الأسئلة.

الأمر المثير للاهتمام هو أن هناك مشكلة أساسية تغطي الفقرة السابقة من هذا القسم (391). هذه المسألة تتعلق عندما تكون الوسيطة هي نفس نوع الفصل. خاصة:

int main () {
  show ( Thing (3) );       // not allowed under current wording
                            // but allowed with Core Issue 391

  show ( 3 );               // Still illegal with 391
}

التغيير في القضية الأساسية 391 يؤثر فقط على حيث يحتوي RValue المؤقت على نفس نوع الفئة. كانت الصياغة السابقة:

إذا كان تعبير التهيئة عبارة عن rvalue ، مع T2 نوع فئة ، و cv1 T1 هو متوافق المرجع مع cv2 T2, المرجع ملزم على النحو التالي:

[...]

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

هذا السطر الأخير هو ما يمكن أن يصنعه show(Thing(3)) غير قانوني حسب المعيار الحالي. الصياغة المقترحة لهذا القسم هي:

إذا كان تعبير التهيئة عبارة عن rvalue ، مع T2 نوع فئة ، و "CV1 T1" متوافق مرجعي مع "CV2 T2" ، فإن المرجع مرتبط بالكائن الذي يمثله RValue (انظر 3.10 [basic.lval]) أو إلى كائن فرعي داخل هذا الكائن.

في هذه المرحلة ، اعتبرت أن G ++ قد يكون قد قام بتحديث سلوكه وفقًا 391 ولكن هذا التغيير شمل بطريق الخطأ حالة نسخ التخصيص. ومع ذلك ، لا يظهر هذا من خلال إصدارات G ++ التي اختبرتها:

class A{
public:
  A ();
  A (int);
private:
  A (A const &);
};

void foo (A const &);

void foo ()
{
  A a = 3 ;     // 3.2.3 (ERROR), 3.4.6(ERROR), 4.4.0(ERROR), Comeau(ERROR)

  foo ( 3 ) ;   // 3.2.3 (OK), 3.4.6(OK), 4.4.0(OK), Comeau(OK)
  foo ( A() );  // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
  foo ( A(3) ); // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
}

لا يمكنني العثور على خطأ في تفسير جيري ل foo (3) ومع ذلك ، لدي شكوك بسبب التناقض بين سلوكيات المترجم المختلفة.

ماذا يحدث إذا حاولت تسمية الشيء المؤقت؟

Thing temp(3);
show(temp);

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