سؤال

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

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

هل هناك طريقة لتجنب انسداد البرمجية سيئة مؤقتة المتغيرات ؟ أود أن تجنب أشياء مثل التالية:

scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);
xyz.initialize_computation(useless_temp);

أنا يمكن أن يجعل المسودة جوهريا mutable ومجرد تسمية جميع المعلمات const &, لكن هذا لا يبدو لي أفضل الممارسات بما انها مضللة ، وأنا لا يمكن أن تفعل هذا لفئات لا السيطرة تماما.مرورا rvalue المرجعية تتطلب إضافة الزائدة إلى جميع المستهلكين من المسودة ، وهو نوع من الهزائم الغرض - وبعد واضحة وموجزة رمز.

نظرا لحقيقة أن الأداء ليست حرجة (ولكن حجم التعليمات البرمجية و القراءة) ، ما هي أفضل الممارسات نهج يمر في هذه المسودة? باستخدام C++0x الميزات هو موافق إذا مطلوب ولكن يفضل C++03-فقط الميزات ينبغي أن يكون كافيا.

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

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

المحلول

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

class scratchpad_t
{
    // ...

public:

    scratchpad_t& self()
    {
        return *this;
    }
};

void foo(scratchpad_t& r)
{
}

int main()
{
    foo(scratchpad_t().self());
}

لاحظ كيف أن الدعوة إلى self() ينتج أحد lvalue التعبير على الرغم من scratchpad_t هو rvalue.

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

حسنا, هل يمكن استخدام قوالب...

template <typename Scratch> void foo(Scratch&& scratchpad)
{
    // ...
}

إذا كنت استدعاء foo مع rvalue المعلمة ، Scratch سوف يستنتج أن scratchpad_t, وبالتالي Scratch&& سوف يكون scratchpad_t&&.

و إذا كنت الاتصال foo مع lvalue المعلمة ، Scratch سوف يستنتج أن scratchpad_t&, و لأن المرجعية انهيار النظام ، Scratch&& كما سيتم scratchpad_t&.

علما بأن المعلمة الرسمية scratchpad هو اسم وبالتالي lvalue, لا يهم إذا كان لها نوع lvalue إشارة أو rvalue المرجعية.إذا كنت ترغب في تمرير scratchpad إلى وظائف أخرى لا تحتاج قالب خدعة للحصول على تلك الوظائف بعد الآن, لقد lvalue مرجع المعلمة.

بالمناسبة, هل تدرك أن المؤقتة المسودة المشاركة في xyz.initialize_computation(scratchpad_t(1, 2, 3)); سيتم تدميرها في أقرب وقت initialize_computation يتم ذلك, صحيح ؟ تخزين الإشارة داخل xyz الكائن في وقت لاحق المستخدم سيكون فكرة سيئة للغاية.

self() لا تحتاج إلى أن تكون عضوا في الطريقة ، يمكن أن يكون قالب وظيفة

نعم, هذا ممكن أيضا ، على الرغم من أن تسميته إلى جعل نية أكثر وضوحا:

template <typename T>
T& as_lvalue(T&& x)
{
    return x;
}

نصائح أخرى

هي المشكلة فقط أن هذا:

scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);

هل القبيح؟ إذا كان الأمر كذلك ، فلماذا لا تغيره إلى هذا؟:

auto useless_temp = factory(rng_parm);

شخصيا ، أفضل أن أرى const_cast من mutable. عندما أرى mutable, ، أنا أفترض أن شخصًا ما منطقي const-ولا تفكر كثيرًا. const_cast ومع ذلك يرفع أعلام حمراء ، مثل هذا الرمز.

خيار واحد هو استخدام شيء مثل shared_ptr (auto_ptr سوف يعمل اعتمادا على ماذا factory هو القيام به) وتمريرها بالقيمة ، والتي تتجنب تكلفة النسخ وتحافظ على مثيل واحد فقط ، ولكن يمكن تمريره من طريقة المصنع الخاصة بك.

إذا قمت بتخصيص الكائن في الكومة ، فقد تتمكن من تحويل الرمز إلى شيء مثل:

std::auto_ptr<scratch_t> create_scratch();

foo( *create_scratch() );

المصنع يخلق ويعيد auto_ptr بدلا من كائن في المكدس. عاد auto_ptr سوف تأخذ مؤقتة ملكية الكائن ، ولكن يُسمح لك بالاتصال بالأساليب غير المؤقتة على مؤقت ويمكنك أن تضعف المؤشر للحصول على مرجع حقيقي. في نقطة التسلسل التالية ، سيتم تدمير المؤشر الذكي وتحرير الذاكرة. إذا كنت بحاجة لتمرير نفس الشيء scratch_t إلى وظائف مختلفة على التوالي ، يمكنك فقط التقاط المؤشر الذكي:

std::auto_ptr<scratch_t> s( create_scratch() );
foo( *s );
bar( *s );

يمكن استبدال هذا بـ std::unique_ptr في المعيار القادم.

لقد وضعت علامة على استجابة Fredoverflow كإجابة على اقتراحه لاستخدام طريقة لإعادة مرجع غير مؤهل ؛ هذا يعمل في C ++ 03. يتطلب هذا الحل طريقة عضو لكل نوع يشبه لوحة الخدش ، ولكن في C ++ 0x يمكننا أيضًا كتابة هذه الطريقة بشكل عام لأي نوع:

template <typename T> T & temp(T && temporary_value) {return temporary_value;}

تقوم هذه الوظيفة ببساطة بإعادة توجيه المراجع العادية LVALUE ، وتحول مراجع RVALUE إلى مراجع LVALUE. بطبيعة الحال ، فإن القيام بذلك يعيد قيمة قابلة للتعديل يتم تجاهل نتائجها - والتي تحدث بالضبط ما أريد ، ولكن قد يبدو غريباً في بعض السياقات.

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