سؤال

لدي سؤال حول بعض الامتثال القياسي C ++ أو عدم وجوده.

في مشروعي ، أستخدم بعض فئة الحراسة البسيطة التي تستخدم خدعة Const Reference. أنا أستخدم Visual Studio 2005 وهناك تكوينان - أحدهما لبناء الإصدار العادي والثاني لاختبارات الوحدة.

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

ولكن بالنسبة لاختبار الوحدة ، يتم نسخ TEMPLATE قالب الوظيفة أولاً ثم يتم استدعاء المدمر ، وفعل ما ينبغي القيام به فقط بعد أن تخرج مرجع const عن النطاق.

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

هل السلوك المعياري المتوافق مع المعيار؟ هل يخبر المعيار أن مرجع const يجب أن يشير مباشرة إلى درجة الحرارة ، أم أن هذا السلوك المعرفة من قبل التنفيذ غير محدد في المعيار؟

لقد استندت إلى رمزتي تقريبًا على مقالة حارس النطاق في مقالة DDJ و Herb Sutter's GOTW 88 ، ولكن يبدو أن هذين المصدرين لا يتناولان مكالمة المدمرة السابقة في الاعتبار.

سيتم تقدير أي معلومات من شخص أكثر دراية.

تعديل:

حسنًا ، الرمز شيء من هذا القبيل:

class GuardBase
{
public:

  GuardBase() : m_enabled(true)
  {}

  //this is done because in normal build no copy constructor is called ( directly using the function temporary)
  //but for UT conf somehow the original temp is copied and destroyed
  GuardBase(const GuardBase& other)
  {
    other.disable();
  }

  void disable() const
  {
    m_enabled = false;
  }

protected:
  //member is mutable because we will access the object through the const reference
  mutable bool m_enabled;
};

template< typename Arg, typename ObjType, typename MemberMethod >
class Guard1Arg : public GuardBase 
{
public:
  Guard1Arg(ObjType& obj, MemberMethod remover,  Arg arg) : m_arg(arg), m_remover(remover), m_object(obj)
  {}

  ~Guard1Arg()
  {
    if ( m_enabled )
    {
      (m_object.*m_remover)(m_arg);
    }
  }

private:
  Arg m_arg;
  MemberMethod m_remover;
  ObjType& m_object;

  //this class should not be assigned
  Guard1Arg& operator=(const Guard1Arg& other);

};

//utility template function used to create Guards using member functions with 1 argument
template<typename MemberFunction, typename Obj, typename Arg>
Guard1Arg<Arg, Obj, MemberFunction> MakeGuard1Arg(Obj& obj, MemberFunction memberFunction, Arg& arg)
{
  return Guard1Arg<Arg, Obj, MemberFunction>(obj, memberFunction, arg);
}


#define GUARD_CREATE(arg, remover) const GuardBase& guard = MakeGuard1Arg(*this,  remover, arg);
#define GUARD_DISABLE guard.disable();
#define GUARD_FRIEND template< typename Arg, typename ObjType, typename MemberMethod > friend class Guard1Arg;
هل كانت مفيدة؟

المحلول

كلا السلوكيات هي معايير مطابقة. إذا كان لديك رمز مثل هذا:

T foo()
{
  return T();
}

int main()
{
  const T& x = foo();
}

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

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

الأقسام ذات الصلة من معيار C ++ هي 6.6.3 ([STMT.RETURN]) و 12.2 ([class.temporary]).

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