لماذا نسخ المسند المستخدمة في هذا الرمز؟

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

  •  06-09-2019
  •  | 
  •  

سؤال

class A
{
 public:
  A(const int n_);
  A(const A& that_);
  A& operator=(const A& that_);
};

A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }

A::A(const A& that_)    // This is line 21
{ cout << "A::A(const A&)" << endl; }

A& A::operator=(const A& that_)
{ cout << "A::operator=(const A&)" << endl; }

int foo(const A& a_)
{ return 20; }

int main()
{
  A a(foo(A(10)));    // This is line 38
  return 0;
}

تنفيذ هذا الرمز يعطي O / P:

a :: a (int)، n_ = 10
a :: a (int)، n_ = 20

يبدو أن منشئ النسخ لا يسمى أبدا.

class A
{
 public:
  A(const int n_);
  A& operator=(const A& that_);
 private:
  A(const A& that_);
};

ومع ذلك، إذا كنا نصنعها خاصة، يحدث هذا الخطأ "

test.cpp: في الوظيفة "int الرئيسية ()":
test.cpp: 21: خطأ: 'a :: a (const a &) هو خاص
test.cpp: 38: خطأ: في هذا السياق

لماذا يشكو المحول البرمجي عندما لا يستخدم بالفعل منشئ النسخ؟
أنا أستخدم نسخة خليجية 4.1.2 20070925 (قبعة حمراء 4.1.2-33)

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

المحلول

العيوب الأساسية 391. يفسر القضية.

في الأساس، يتطلب معيار C ++ الحالي أن يتوفر منشئ نسخ عند تمرير نوع مؤقت من النوع إلى مرجع Const.

سيتم إزالة هذا الشرط في C ++ 0x.

المنطق وراء مطالبة منشئ نسخة يأتي من هذه الحالة:

C f();
const C& r = f(); // a copy is generated for r to refer to

نصائح أخرى

الولايات 2003، في الفقرة 12.2 / 1، الولايات:

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

هناك أمثلة مماثلة حولها. من ما أجمع، التحويل البرمجي مجاني لتوليد مؤقتا أو تحسينها بعيدا.

بقدر ما أراك لا تستخدم منشئ النسخ في أي مكان. في البيان foo(A(10)) أنت تقوم بإنشاء كائن مؤقت من الفئة A واجتيازها كمرجع غير مؤتمر إلى FOO. إرجاع FOO عدد صحيح يستخدم في بناء الكائن a. وبعد وبالتالي، لا أرى حيث يتورط منشئ النسخ هنا وكيف يأتي nrvo في الصورة. أيضا، قمت بتجميع التعليمات البرمجية التالية عن طريق إنشاء منشئ نسخ خاص وتجميعها غرامة في VS2008.

using namespace std;

class A
{
 public:
  A(const int n_);
 private:
  A(const A& that_);
  A& operator=(const A& that_);
};

A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }

A::A(const A& that_)    // This is line 21
{ cout << "A::A(const A&)" << endl; }

A& A::operator=(const A& that_)
{ 
    cout << "A::operator=(const A&)" << endl; 
    return *this;
}

int foo(const A& a_)
{ return 20; }


int main(int argc,char *argv[])
{
   A a(foo(A(10)));    // This is line 38
  return 0;

}   

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

A original(10);
foo( original ); // does compile
foo( A(10) ); // doesn't compile - needs a copy constructor

في التعبير:

A a(foo(A(10)));

نتيجة التعبير الفرعي A(10) هو rvalue. من النوع A. وبعد (5.2.3 [expr.type.conv])

عند تهيئة إشارة الاتصال من rvalue. قد يخلق المحول البرمجي مؤقتا من rvalue. وربط ذلك بالرجوع إليها. حتى لو اختار عدم ذلك، يجب الوصول إلى منشئ النسخ. (8.5.3 [decl.init.ref]) لن يكون هذا هو الحال إذا تم تهيئة الإشارة من متوافق مرجعي lvalue. حيث يتم تكليف التجليد المباشر.

كما foo يأخذ المعلمة حسب المرجع وليس القيمة، لا توجد نسخة مفوضة لتهيئة الحجة نفسها.

foo إرجاع int، لذلك لا توجد نسخة من A هنا.

a يتم تهيئته مباشرة من int الذي تم إرجاعه بواسطة FOO، لذلك لا توجد نسخة من A هنا.

لا يتم استخدام منشئ النسخ، ولكن لكي يحتاج التعليمات البرمجية لتجميع النسل إلى الوصول إلى الملاحظات.

تحرير: تقارير Comeau C ++ برنامج التحويل البرمجي ما يلي:

Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 38: error: "A::A(const A &)" (declared at line 17), required
          for copy that was eliminated, is inaccessible
    A a(foo(A(10)));    // This is line 38
            ^

1 error detected in the compilation of "ComeauTest.c".

لاحظ أنه إذا تم تمكين ملحقات C ++ 0x، فإنها تتجمع بشكل جيد في مترجم Comeau C ++.

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

عند الاتصال:

foo( A(10) );

يتم إنشاء كائن مؤقت أثناء حياة المكالمة. يتم استخدام منشئ النسخ لملء البيانات. تتم إزالة الكائن المؤقت بعد تنفيذ المكالمة.

عند الاتصال:

{ 
  A original(10);
  foo( original ); 
}

يتم التخلص من الأصل بعد الخروج من الكتلة. يمكن أن تستخدم بأمان كمعلمة.

للحصول على السرعة المثلى، اجتاز الكائن حسب المرجع، باستخدام متغير مؤقت يتم تجاهله بواسطة المحول البرمجي أثناء التحسين.

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