วิธีจัดการกับการเปลี่ยนแปลงการออกแบบสำหรับการเลิกใช้งาน auto_ptr ใน C ++ 11 ได้อย่างไร


12

เรากำลังทดสอบห้องสมุดภายใต้ C ++ 11 (เช่น-std=c++11) ห้องสมุดใช้auto_ptrและรูปแบบนี้:

Foo* GetFoo()
{
    autoptr<Foo> ptr(new Foo);

    // Initialize Foo
    ptr->Initialize(...);

    // Now configure remaining attributes
    ptr->SomeSetting(...);

    return ptr.release();
}

เลิกใช้ C ++ 11 auto_ptrดังนั้นเราต้องการย้ายออกไป

อย่างไรก็ตามรหัสสนับสนุนทั้ง C ++ 03 และ C ++ 11 จึงไม่ง่ายที่เป็น auto_ptryanking นอกจากนี้ยังมีมูลค่าการกล่าวถึงห้องสมุดที่ไม่มีการอ้างอิงภายนอก มันใช้ C ++ 03; และไม่ใช้ Autotools, Cmake, Boost, ...

เราควรจัดการกับการเปลี่ยนแปลงการออกแบบเพื่อย้ายออกจากauto_ptrสำหรับ C ++ 11 ในขณะที่รักษาความเข้ากันได้กับ C ++ 03 ได้อย่างไร


มีauto_ptrขอบเขตใด ๆ(เช่นstd::auto_ptr) พวกเขาจำเป็นต้องเป็นหรือสามารถรับตัวชี้สมาร์ทได้จาก namespace อื่น ๆ ?
Niall

เช่นกันคุณอาจต้องการที่จะพับลงไปFoo::Initialize Foo::Foo
MSalters

1
@Malters - ใช่นั่นเป็นหนึ่งในสิ่งที่ฉันรู้สึกอึดอัดเล็กน้อย ห้องสมุดได้รับการออกแบบในปี 1990 และฉันคิดว่าการออกแบบคล้ายกับ MFC นั่นคือมีการก่อสร้าง C ++ ระดับต่ำกว่าและจากนั้นการสร้างวัตถุ "ระดับที่สูงขึ้น" ฉันคิดว่าฟีเจอร์นี้ใช้เป็นข้อแลกเปลี่ยนเพื่อให้คลาสไม่มีคอนสตรัคเตอร์ที่แตกต่างกัน 6 หรือ 12 ตัว (ณ จุดนี้สิ่งที่ฉันได้ทำผ่านไปแล้วและทำให้มั่นใจว่าตัวแปรสมาชิกประเภท POD ถูกเตรียมใช้งานให้เป็นค่าเริ่มต้นที่มีสติในคอนสตรัคเตอร์ C ++)

คำตอบ:


13

ในการเคารพมากที่สุดstd::unique_ptrที่จะต้องลดลง ( แต่ปลอดภัยกว่า) แทนstd::auto_ptrดังนั้นควรจะมีน้อยมาก (ถ้ามี) การเปลี่ยนแปลงรหัสอื่น ๆ ที่จำเป็นกว่า (ตามที่คุณถาม) กำกับรหัสเพื่อการใช้งานอย่างใดอย่างหนึ่งหรือunique_ptrauto_ptr

มีสองสามวิธีในการทำสิ่งนี้ (และแต่ละรายการมาพร้อมกับการแลกเปลี่ยนรายชื่อของตนเอง) ด้านล่าง เมื่อได้รับตัวอย่างโค้ดที่ให้มาฉันจะให้ทางเลือกหนึ่งในสองตัวเลือกแรก

ตัวเลือกที่ 1

#if __cplusplus >= 201103L
template <typename T>
using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif

สมดุล;

  • คุณแนะนำauto_ptrชื่อลงใน namespace ส่วนกลาง คุณสามารถลดสิ่งนี้ได้โดยกำหนดเป็นเนมสเปซ "ส่วนตัว" ของคุณเอง
  • เมื่อย้ายไปที่ C ++ 17 (ฉันเชื่อว่าauto_ptrจะถูกลบออกอย่างสมบูรณ์) คุณสามารถค้นหาและแทนที่ได้ง่ายขึ้น

ตัวเลือก 2

template <typename T>
struct my_ptr {
    #if __cplusplus >= 201103L
    typedef std::unique_ptr<T> ptr;
    #else
    typedef std::auto_ptr<T> ptr;
    #endif
};

สมดุล;

  • อาจยุ่งยากกว่าในการทำงานกับทุกความauto_ptrต้องการปัจจุบันในการเปลี่ยนรหัสเป็นสิ่งที่ต้องการmy_ptr<T>::ptr
  • ความปลอดภัยที่ดีขึ้นชื่อจะไม่ถูกนำเข้าสู่ namespace ทั่วโลก

ตัวเลือก 3

ค่อนข้างขัดแย้ง แต่ถ้าคุณพร้อมที่จะรับมือกับคำเตือนของการมีstdชั้นเรียนเป็นฐาน

#if __cplusplus >= 201103L
template <typename T>
using my_ptr = std::unique_ptr<T>;
#else
template <typename T>
class my_ptr : public std::auto_ptr<T> {
  // implement the constructors for easier use
  // in particular
  explicit my_ptr( X* p = 0 ) : std::auto_ptr(p) {}
};
#endif

สมดุล;

  • อย่าพยายามใช้คลาสที่สืบทอดมาซึ่งฐานเสมือน (โดยเฉพาะ wrt ตัวทำลายระบบเสมือน) จะต้องถูกคาดหวัง ไม่ใช่ว่านี่ควรจะเป็นปัญหาในกรณี - แต่ระวังให้ดี
  • การเปลี่ยนแปลงรหัสอีกครั้ง
  • ศักยภาพเนมสเปซที่ไม่ตรงกัน - ขึ้นอยู่กับวิธีการใช้คลาสพอยน์เตอร์เริ่มต้นด้วย

ตัวเลือก 4

ล้อมรอบพอยน์เตอร์ในคลาสใหม่และรวมฟังก์ชันที่จำเป็นเข้ากับสมาชิก

template <typename T>
class my_ptr { // could even use auto_ptr name?
  #if __cplusplus >= 201103L
  std::unique_ptr<T> ptr_;
  #else
  std::auto_ptr<T> ptr_;
  #endif

  // implement functions required...
  T* release() { return ptr_.release(); }
};

สมดุล;

  • สุดขีดเล็กน้อยเมื่อสิ่งที่คุณต้องการจริงๆคือ "สลับ" การใช้งานออกไป

คำตอบที่ดีมาก จริง ๆ แล้วฉันวิจัยมันเล็กน้อยและคุณตีอย่างน้อยสามการทดสอบที่ฉันพยายาม (สิ่งที่คุณขาดคือสิ่งเฉพาะของ OS X และ Clang OS X เป็นหมีเพราะยังคงใช้เนมสเปซ TR1 สำหรับ C ++ 03 ในแต่ละครั้งและคุณต้องรวมสิ่งต่าง ๆ โดยใช้วิธีนี้: ไม่มีประเภทชื่อ 'unique_ptr' ในเนมสเปซ 'std' เมื่อรวบรวมภายใต้ LLVM / Clang )

@jww ฉันใช้ OS X (XCode 6.4 และ Apple LLVM เวอร์ชัน 6.1.0 (clang-602.0.53) (อ้างอิงจาก LLVM 3.6.0svn) และไม่มีปัญหากับการผสม C ++ 03/11 นอกเหนือจากtr1namespace no อยู่ที่นั่นอีกต่อไป (ฉันใช้ libc ++ และไม่ใช่ libstdc ++) ฉันรู้ว่า tr1 นั้นไม่ปกติ แต่ฉันไม่สามารถหาได้ทุกที่ในแบบร่าง (ที่นี่)ว่าไฟล์จะต้องเป็น<tr1/...>อย่างใดเลย infact กล่าวถึงเพียงแค่ในส่วนหัวของ<memory>ไฟล์ ฯลฯ ในtr1เนมสเปซ
Niall

@jww ฉันเดาว่าให้คอมไพเลอร์ไลบรารีและอุปกรณ์เป้าหมายโดยเฉพาะ - คุณอาจต้องใช้มืออีกสองสามอัน อื่นบน OS X ลองย้ายไปที่เสียงดังกราวและ libc ++ ฉันคิดว่า libc ++ เป็นไลบรารี่ "C ++" ใหม่สำหรับ OS X - ฉันจะใช้ค่าเริ่มต้น ฉันไม่มีวิธีที่จะสนับสนุนข้อเรียกร้องเหล่านี้อื่น ๆ ที่ประวัติความสัมพันธ์ของ clang / Apple และเครื่องมือ GCC บน OS X ดูล้าสมัย (ไลบรารี่) หรือเพิ่งลบออก (เท่าที่ฉันรู้ GCC เป็น stub บาง ๆ )
Niall

"อื่น ๆ บน OS X ลองย้ายไปที่เสียงดังกราวและ libc ++ ... " - ใช่ฉันเห็นด้วยกับคุณ อย่างไรก็ตามเราต้องการให้ผู้ใช้เลือกได้และไม่บังคับให้ผู้ใช้ (พวกเขาเลือกโดยปริยายเมื่อพวกเขาระบุ (หรือขาด) CXX=...)

นี่เป็นกรณีที่เป็นสาเหตุของผมปัญหามากใน OS X 10.7 และ c++ -v -std=c++11 -x c++ - < /dev/null10.8: ฉันgrep'dรวมถึงไดเรกทอรีที่ถูกทิ้งและพวกเขาไม่ได้unique_ptrรวมถึง

0

ตัวเลือกที่ 5: นามแฝงโดยตรง

#if __cplusplus >= 201103L
template<typename T> 
using MyPtr = std::unique_ptr<T>;
#else 
#define MyPtr std::auto_ptr
#endif 

สมดุล:

  1. สำหรับเวอร์ชันภาษาที่ใหม่กว่า AKA C ++ 11 และใหม่กว่าประเภทนามแฝงของคุณจะแมปกับตัวชี้สมาร์ทที่ถูกต้อง รหัสผู้ใช้ใด ๆ ที่ขึ้นอยู่กับ API เฉพาะสำหรับ std :: auto_ptr จะได้รับการตั้งค่าสถานะโดยคอมไพเลอร์ซึ่งเป็นการรับประกันขั้นสุดท้ายว่าจะได้รับการแก้ไขจริงๆ

  2. ในโหมด Legacy c ++ 03 นามแฝงประเภทคือแมโคร นี่คือขั้นต้น แต่ไวยากรณ์ผลลัพธ์MyPtr<T>จะเหมือนกับกรณี C ++ 11 ตลอดทั้งรหัสที่เหลือ

  3. คุณต้องค้นหาและเปลี่ยนตัวแปร auto_ptr ทั้งหมดของคุณMyPtrเพื่อตั้งค่านี้


1
มันไม่ชัดเจนว่านี่คือการอ้างอิงอะไร (และตามที่ใช้ถ้อยคำแล้วมันก็ไม่ใช่คำถาม)
autophage

1
@ Autoophage ฉันเชื่อว่ามันเป็นคำตอบ ... ดังนั้นอาจไม่ใช่คำถาม
Kain0_0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.