มีปัญหาที่แท้จริงกับไลบรารีที่ใช้ร่วมกันซึ่งสำนวนของ pimpl จะหลีกเลี่ยงอย่างเรียบร้อยซึ่งเวอร์ชวลที่แท้จริงทำไม่ได้: คุณไม่สามารถแก้ไข / ลบสมาชิกข้อมูลของคลาสได้อย่างปลอดภัยโดยไม่บังคับให้ผู้ใช้ในคลาสคอมไพล์โค้ดของพวกเขาใหม่ ซึ่งอาจยอมรับได้ในบางสถานการณ์ แต่ไม่ใช่เช่นสำหรับไลบรารีระบบ
ในการอธิบายปัญหาโดยละเอียดให้พิจารณารหัสต่อไปนี้ในไลบรารี / ส่วนหัวที่ใช้ร่วมกันของคุณ:
// header
struct A
{
public:
A();
// more public interface, some of which uses the int below
private:
int a;
};
// library
A::A()
: a(0)
{}
รหัสเรียบเรียงส่งเสียงในห้องสมุดที่ใช้ร่วมกันที่คำนวณอยู่ของจำนวนเต็มที่จะเริ่มต้นที่จะเป็นบางชดเชย (อาจเป็นศูนย์ในกรณีนี้เพราะมันเป็นสมาชิกเท่านั้น) this
จากตัวชี้ไปยังวัตถุที่รู้ว่าจะเป็น
ในด้านของผู้ใช้รหัสที่เป็นnew A
ครั้งแรกที่จะจัดสรรsizeof(A)
ไบต์หน่วยความจำแล้วมือชี้ไปยังหน่วยความจำที่ให้กับตัวสร้างเป็นA::A()
this
หากในการแก้ไขไลบรารีของคุณในภายหลังคุณตัดสินใจทิ้งจำนวนเต็มทำให้ใหญ่ขึ้นเล็กลงหรือเพิ่มสมาชิกจะมีความไม่ตรงกันระหว่างจำนวนรหัสของผู้ใช้หน่วยความจำที่จัดสรรและค่าชดเชยที่โค้ดตัวสร้างคาดไว้ ผลลัพธ์ที่เป็นไปได้คือความผิดพลาดหากคุณโชคดี - หากคุณโชคดีน้อยกว่าซอฟต์แวร์ของคุณจะทำงานผิดปกติ
โดย pimpl'ing คุณสามารถเพิ่มและลบสมาชิกข้อมูลไปยังคลาสภายในได้อย่างปลอดภัยเนื่องจากการจัดสรรหน่วยความจำและการเรียกตัวสร้างเกิดขึ้นในไลบรารีที่ใช้ร่วมกัน:
// header
struct A
{
public:
A();
// more public interface, all of which delegates to the impl
private:
void * impl;
};
// library
A::A()
: impl(new A_impl())
{}
สิ่งที่คุณต้องทำตอนนี้คือทำให้อินเทอร์เฟซสาธารณะของคุณปราศจากข้อมูลสมาชิกนอกเหนือจากตัวชี้ไปยังอ็อบเจ็กต์การนำไปใช้งานและคุณจะปลอดภัยจากข้อผิดพลาดระดับนี้
แก้ไข:ฉันควรจะเพิ่มว่าเหตุผลเดียวที่ฉันพูดถึงตัวสร้างที่นี่คือฉันไม่ต้องการให้รหัสเพิ่มเติม - อาร์กิวเมนต์เดียวกันนี้ใช้กับฟังก์ชันทั้งหมดที่เข้าถึงสมาชิกข้อมูล