سؤال

يعمل الكود التالي فقط عند توفر منشئ النسخ.

عندما أضيف عبارات الطباعة (عبر std::cout) وجعل إنشاء منشئ النسخ غير مستخدم لا يستخدم (أفترض أن هناك خدعة مترجم لذلك تحدث لإزالة النسخة غير الضرورية).

ولكن في كل من الإخراج operator << والوظائف plop() أدناه (حيث أقوم بإنشاء كائن مؤقت) لا أرى الحاجة إلى منشئ النسخ. يمكن لشخص ما يفسر لماذا تحتاج اللغة إلى ذلك عندما أتخبت كل شيء عن طريق الإشارة إلى الإشارة (أو ما أقوم به خطأ).

#include <iostream>

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

std::ostream& operator<<(std::ostream& str,N const& data)
{
    return str << "N\n";
}

void plop(std::ostream& str,N const& data)
{
    str << "N\n";
}

int main()
{
    std::cout << N(1);     // Needs copy constructor  (line 25)
    plop(std::cout,N(1));  // Needs copy constructor

    N    a(5);
    std::cout << a;
    plop(std::cout,a);
}

مترجم:

ألفا: ~ / x] myork٪ g ++
باستخدام المواصفات المدمجة.
الهدف: I686-Apple-Darwin10
تم تكوينه مع: / Var / TMP / GCC / GCC-5646 ~ 6 / SRC / تكوين - التحقق من عدم قابلية الفحص - Werror - Werror - PREFIX = / USR - ممرض = / SHARE / MAN - LANGAND = C ، OBJC، C ++، OBJ-C ++ - تحويل البرنامج = / ^ [CG] [^ .-] * $ / s / $ / - 4.2 / with-slibdir = / usr / lib - build = i686-apple-darwin10 - with-gxx-fince-dir = dir = / conced / c ++ / 4.2.1 - prefix-prefix = i686-apple-darwin10- --host = x86_64-apple-darwin10 - اختبار = i686- Apple-Darwin10.
نموذج الموضوع: posix
دول مجلس التعاون الخليجي الإصدار 4.2.1 (Apple Inc. Build 5646)

ألفا: ~ / x] myork٪ g ++ t.cpp
T.CPP: في الوظيفة "Int int الرئيسية ()":
T.CPP: 10: خطأ: 'n :: n (const n &)' هو خاص
T.CPP: 25: خطأ: في هذا السياق
T.CPP: 10: خطأ: 'n :: n (const n &)' هو خاص
T.CPP: 26: خطأ: في هذا السياق

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

تغيير الفصل أيضا:

class N
{
    public:
        N(int)  {}
    private:
        std::auto_ptr<int>  data;
};

الخطأ هو:

t.cpp: 25: خطأ: لا توجد وظيفة مطابقة للمكالمات إلى 'n :: n (n)'

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

المحلول

من http://gcc.gnu.org/gcc-3.4/changes.html.

عند ربط RVALUE من نوع الفصل إلى مرجع، يجب الوصول إلى منشئ النسخ للفئة. على سبيل المثال، فكر في التعليمات البرمجية التالية:

class A 
{
public:
  A();

private:
  A(const A&);   // private copy ctor
};

A makeA(void);
void foo(const A&);

void bar(void)
{
  foo(A());       // error, copy ctor is not accessible
  foo(makeA());   // error, copy ctor is not accessible

  A a1;
  foo(a1);        // OK, a1 is a lvalue
}

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

سيتم إصلاح هذا في C ++ 1X العدد الأساسي 391..

نصائح أخرى

الأجزاء المعمول بها من المعيار هنا هي §8.5.3 / 5، والتي تغطي تهيئة المراجع و §3.10 / 6، والتي تحكي ما هو rvalue وما هو lvalue (ليس واضحا دائما في C ++).

في هذه الحالة، تقوم بتهيئة التعبير هو: "ن (1)"، لذلك تقوم بإنشاء كائن يستخدم صراحة باستخدام تدوين وظيفي. وفقا ل 3.10 / 6، هذا التعبير هو rvalue.

ثم يتعين علينا المشي من خلال القواعد في 8.5.3 / 5 في النظام، واستخدام الأول الذي ينطبق. الاحتمال الأول هو إذا كان التعبير يمثل lvalue، أو يمكن تحويلها ضمنا إلى lvalue. تعبيرك هو RValue، والتحويل الضمني إلى Lvalue سيتطلب وظيفة تحويل تعياف مرجع، والذي لا يبدو أنه موجود في هذه الحالة، لذلك لا يبدو أنه ينطبق.

تقول القاعدة التالية إن الإشارة يجب أن يكون في const t (وهذا هو الحال هنا). في هذه الحالة، يعد التعبير عبارة عن RValue من نوع الفصل وهو متوافق مع الإشارة (أي المرجع إلى نفس الفصل، أو قاعدة للفئة). هذا يعني أن الرصاصة في أسفل الصفحة 151 (179 من PDF C ++ 2003) يبدو أنها تنطبق. في هذه الحالة، يسمح للمترجم بإما ربط المرجع مباشرة بالكائن الذي يمثل RVALUE، أو إنشاء نسخة مؤقتة من RVALUE، وربطها بتلك النسخة المؤقتة.

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

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

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

void plop(N const& data) { }

int main() {
    plop(N(1));
}

عند استدعاء "-" (وضع الأخطاء الصارمة)، يعطي COMEAU رسالة الخطأ التالية:

"plop.cpp", line 12: error: "N::N(const N &)", required for copy that was
          eliminated, is inaccessible
      plop(N(1));
           ^

وبالمثل، عند استدعاء "/ ZA" (وضع "ANSI المطابق")، يعطي VC ++ 9:

plop.cpp
plop.cpp(12) : error C2248: 'N::N' : cannot access private member declared in class 'N'
        plop.cpp(6) : see declaration of 'N::N'
        plop.cpp(2) : see declaration of 'N'
        while checking that elided copy-constructor 'N::N(const N &)' is callable
        plop.cpp(6) : see declaration of 'N::N'
        when converting from 'N' to 'const N &'

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

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