หลีกเลี่ยงการมีวิธีการเริ่มต้น


12

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

เหตุผลทำไมมีวิธีการเตรียมใช้งาน วัตถุที่ถูกสร้างขึ้นก่อนที่จะมีขอบเขตทั่วโลกและจากนั้นวิธีการเริ่มต้นได้รับการเรียกในภายหลังหลังจากโหลด dll ซึ่งมันขึ้นอยู่กับ

ปัญหาเกี่ยวกับการเริ่มต้น คลาสตอนนี้มีบูล isInitialized ซึ่งจำเป็นต้องตรวจสอบในทุกวิธีก่อนที่จะดำเนินการและส่งกลับข้อผิดพลาดหากไม่ได้เริ่มต้น พูดง่ายๆคือมันเป็นความเจ็บปวดครั้งใหญ่

ทางออกหนึ่งที่เป็นไปได้ เริ่มต้นในตัวสร้าง มีเพียงตัวชี้ไปยังวัตถุในขอบเขตส่วนกลาง สร้างวัตถุจริงหลังจากที่โหลด dll

ปัญหาเกี่ยวกับการแก้ปัญหาข้างต้น ทุกคนที่สร้างวัตถุของคลาสนี้จำเป็นต้องรู้ว่ามันจะต้องมีการสร้างหลังจากโหลด dll หรือมิฉะนั้นมันจะล้มเหลว

เป็นที่ยอมรับหรือไม่?


ฉันมีปัญหาเดียวกันนี้เมื่อสร้างวัตถุที่เกี่ยวข้องกับ OpenGL ซึ่งจำเป็นต้องมีอินสแตนซ์ก่อนที่จะมีบริบทของ OpenGL อยู่ แต่ควรถือ OpenGL วัตถุเช่นรายการโทรพื้นผิว ฯลฯ

3
คำถามโง่ # 1: ทำไมตัวสร้างวัตถุไม่สามารถโหลด DLL ได้หากยังไม่ได้โหลด
John R. Strohm

1
ขอโทษสำหรับการรื้อฟื้นคำถามเก่า แต่ในกรณีที่ทุกคนที่อ่านข้อความนี้ในปี 2017, การใช้งานcall_onceใน C โครงการที่ไม่ได้อยู่ใน C ++ 11 ควรศึกษาว่า call_once ถูกนำไปใช้ใน C ++ 11 ได้อย่างไร (เน้นที่ปัญหาที่แก้ได้และวิธีการ) แล้วนำไปใช้ใหม่ในรสชาติ (เก่า) ของ C ++ มันจำเป็นต้องมีการซิงโครไนซ์ที่ปลอดภัยแบบหลายเธรดแบบดั้งเดิมซึ่งรัฐจะต้องเริ่มต้นแบบคงที่ (ด้วยค่าคงที่) โปรดทราบว่าคอมไพเลอร์ pre-C ++ 11 อาจมี idiosyncrasies อื่น ๆ ที่จำเป็นต้องได้รับ

คำตอบ:


7

ฟังดูเหมือนเป็นงานสำหรับพรอกซีเสมือน

คุณสามารถสร้างพร็อกซีเสมือนที่มีการอ้างอิงถึงวัตถุที่เป็นปัญหา ในขณะที่ไม่มีการโหลด DLL พร็อกซีสามารถเสนอพฤติกรรมเริ่มต้นที่แน่นอนให้กับลูกค้าเมื่อโหลด DLL แล้วพร็อกซีจะส่งต่อคำขอทั้งหมดไปยังเรื่องจริง

พร็อกซีเสมือนจะรับผิดชอบในการตรวจสอบการเริ่มต้น DLL และขึ้นอยู่กับการตัดสินใจนี้หากการมอบหมายควรได้รับการมอบหมายให้เป็นเรื่องจริง

รูปแบบหนังสือมอบฉันทะใน Wikipedia

คุณชอบความคิดนี้อย่างไร


คุณไม่ได้แก้อะไรมากที่นี่ สำหรับทุกวิธีที่เพิ่มในวัตถุจริงคุณจะต้องเพิ่มวิธีนั้นในพร็อกซีด้วย ไม่มี?

สิ่งนี้จะช่วยหลีกเลี่ยงปัญหาในการจดจำการเรียกใช้งาน init ฟังก์ชั่น แต่ดูเหมือนว่าทุกฟังก์ชั่นในพร็อกซียังคงต้องตรวจสอบเพื่อดูว่ามีการโหลด. dll

1
@Siriram มีความแตกต่างอย่างมากในขณะนี้การใช้พร็อกซีที่คุณได้ จำกัด การบำรุงรักษาที่เกี่ยวข้องกับการตรวจสอบ DLL เป็นคลาสเดียว: พร็อกซี ลูกค้าของชั้นไม่จำเป็นต้องรู้เกี่ยวกับการตรวจสอบ DLL เลย เนื่องจากวิธีการส่วนใหญ่จะทำการมอบหมายฉันไม่เห็นปัญหามากในการใช้งานอินเทอร์เฟซในทั้งเรื่องจริงในพร็อกซี กล่าวอีกนัยหนึ่งคุณสามารถป้องกันการสร้างเรื่องจริงจนกว่าคุณจะแน่ใจว่าโหลด DLL แล้วและคุณไม่จำเป็นต้องตรวจสอบสถานะ DLL ทุกครั้ง

@edalorzo: ในขณะที่ความคิดเป็นสิ่งที่ดีปัญหาที่นี่คือการที่เรามีอยู่แล้วพูดคุยเกี่ยวกับพร็อกซี่และ OP จะบ่นเกี่ยวกับการมีการตรวจสอบในแต่ละวิธีของพร็อกซี ...
Matthieu เอ็ม

4

ไม่มีประโยชน์ใด ๆ เกิดขึ้นหากยังไม่ได้โหลด DLL วัตถุสร้างข้อผิดพลาดเท่านั้น มันเป็นข้อผิดพลาดร้ายแรงหรือไม่? การจัดการข้อผิดพลาดเป็นอย่างไร?

วิธีการทดสอบของคุณทำให้มั่นใจได้ว่าข้อผิดพลาดนี้จะไม่เกิดขึ้นในผลิตภัณฑ์สำเร็จรูปหรือไม่?

ดูเหมือนว่างานสำหรับการทดสอบไม่ใช่เพื่อการออกแบบสถาปัตยกรรม อย่าเพิ่งกลับข้อผิดพลาดassertมันไม่เคยเกิดขึ้น

แก้ไขไคลเอ็นต์ใด ๆ ของคลาสที่ตรวจจับและละเว้นข้อผิดพลาดในปัจจุบันเพื่อไม่ลองและทำให้เกิดขึ้นในครั้งแรก

รูปแบบมัลติเธรดอาจตั้งค่าตัวแปรเงื่อนไขที่ใช้ร่วมกันหลังจากโหลด DLL และให้ตัวสร้างวัตถุรอ (และบล็อกเธรดอื่น ๆ ) จนกว่าจะโหลด DLL


ฉันคิดว่าคุณพูดถูกไม่มีอะไรผิดปกติกับการโยนข้อยกเว้นเมื่อสร้างวัตถุที่เป็นปัญหาหาก DLL ไม่ได้เริ่มต้นอย่างถูกต้อง รหัสลูกค้าจะต้องจัดการกับข้อยกเว้นนี้เท่านั้นและการทดสอบควรตรวจสอบให้แน่ใจว่ามีการจัดการข้อยกเว้นอย่างเหมาะสม

2

สิ่งแรก: หลีกเลี่ยงวัตถุในโลกเป็นศัตรูพืชเว้นแต่สถานะของพวกเขาจะไม่เปลี่ยนแปลง (การกำหนดค่า)

ทีนี้ถ้าคุณติดกับมันไม่ว่าจะด้วยเหตุผลใดมีการออกแบบหลายอย่างที่อาจช่วยคุณได้

ฉันคิดสองแนวคิด:

  1. ใช้ Facade เพื่อโหลด DLL วัตถุนั้นสามารถเข้าถึงได้ผ่านทาง Facade เท่านั้น Facade จะโหลด DLL เมื่อสร้างและสร้างอินสแตนซ์ของวัตถุในเวลาเดียวกัน

  2. ใช้พร็อกซี แต่เป็นคนฉลาด;)

ให้ฉันอธิบายอย่างละเอียดในประเด็นที่สองเนื่องจากฉันกลัวว่าคำตอบของ@edalorzoอาจทำให้คุณตกใจ:

// Private
static Object& GetObjectImpl() { static Object O; return O; }

// Public
static Object& GetObject() {
  Object& o = GetObjectImpl();
  assert(o.isInitialized() && "Object not initialized yet!");
  return o;
}

ตอนนี้คุณมีเพียงเช็คเดียว

สิ่งนี้สามารถทำได้ผ่านตัวชี้อัจฉริยะบางชนิด:

Pointer<Object> o;

ที่นี่คุณสำรองพื้นที่สำหรับตัวชี้โดยเริ่มแรกเป็นค่าว่างและเฉพาะเมื่อโหลด DLL แล้วคุณจะจัดสรรวัตถุจริงๆ การเข้าถึงก่อนหน้านี้ทั้งหมดควรเพิ่มข้อยกเว้น (NullException: p?) หรือยกเลิกโปรแกรม (หมดจด)


1

นี่เป็นคำถามที่ยุ่งยาก ฉันรู้สึกว่าสถาปัตยกรรมอาจช่วยแก้ไขปัญหาได้

จากหลักฐานดูเหมือนว่า. dll จะไม่ถูกโหลดเมื่อโหลดโปรแกรม มันเกือบจะฟังดูเหมือนปลั๊กอิน

สิ่งหนึ่งที่อยู่ในใจคือคุณต้องเริ่มต้น. dll โปรแกรมเมอร์ต้องสมมติว่าวัตถุจะไม่กลับมาอย่างน่าเชื่อถืออีกต่อไป คุณอาจสามารถใช้ประโยชน์จากสิ่งนี้ ( bool isObjectLoaded() { return isInitialized; }) แต่คุณจะได้รับรายงานข้อผิดพลาดเพิ่มเติมจากเช็คของคุณ

ฉันกำลังคิดของซิงเกิล

ถ้าคุณเรียกใช้ซิงเกิลมันควรจะคืนค่าวัตถุที่ถูกต้องถ้ามันสามารถเรียกคืนได้ หากไม่สามารถส่งคืนวัตถุที่ถูกต้องได้คุณควรได้รับค่าความผิดพลาด / nullptr / วัตถุฐานที่ว่างเปล่า สิ่งนี้จะไม่ทำงานถ้าวัตถุนั้นอาจตายกับคุณได้

นอกจากนี้หากคุณต้องการวัตถุหลายอินสแตนซ์คุณสามารถใช้บางอย่างเช่นโรงงานแทน

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