จะให้ฟังก์ชันที่คาดหวังตัวชี้ดิบได้อย่างไร?

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

  1. ใช้ตัวชี้เฉพาะ - หากพวกเขาตัดสินใจลบตัวชี้ ฉันจะลบสองครั้ง
  2. ติดตามตัวชี้ดิบ - แย่เพราะฉันต้องจำไว้ว่าต้องเขียนลบ แต่อาจเป็นการลบสองครั้ง
  3. ใช้ระยะเวลาอัตโนมัติและให้ตัวชี้ ให้ข้อมูลอ้างอิงแก่พวกเขา - รหัสของพวกเขาจะผิดพลาดหากพวกเขาเรียกลบ
  4. ใช้ตัวชี้ที่ใช้ร่วมกัน - ปัญหาการลบสองครั้งเหมือนกับตัวชี้เฉพาะ แต่ตอนนี้ขอบเขตของฉันจะไม่ทำให้ตัวชี้เสียหาย

จากการอ่านของฉัน ตัวเลือกที่ 3 ดูเหมือนว่าฉันควรทำ - ไม่ควรเรียก Delete บนตัวชี้ และรูปแบบนี้บังคับใช้ แต่ถ้าฉันไม่รู้ว่าตอนนี้หรือในอนาคตพวกเขาจะเรียกลบตามข้อมูลอ้างอิงที่ฉันให้ไว้ล่ะ? ใช้ตัวชี้ที่ใช้ร่วมกันและบอกว่าไม่ใช่ความผิดของฉันเกี่ยวกับการลบสองครั้งใช่ไหม

#include <memory>
#include <iostream>

class ComplexObj {
  public:
    ComplexObj() : m_field(0) {}
    ComplexObj(int data) : m_field(data) {}

    void print() { std::cout << m_field << std::endl; }

  private:
    int m_field;
};

class BlackBox {
  public:
    BlackBox(ComplexObj* data) {
        m_field = *data;

        // Do other things I guess...

        delete data;
        std::cout << "Construction complete" << std::endl;
    }

    void print_data() { m_field.print(); }

  private:
    ComplexObj m_field;
};

int main(int argc, char* argv[]) {
    // Use a smart pointer
    std::unique_ptr<ComplexObj> my_ptr(new ComplexObj(1));
    BlackBox obj1 = BlackBox(my_ptr.get());
    obj1.print_data();
    my_ptr->print();  // Bad data, since BlackBox free'd
    // double delete when my_ptr goes out of scope

    // Manually manage the memory
    ComplexObj* manual = new ComplexObj(2);
    BlackBox obj2 = BlackBox(manual);
    obj2.print_data();
    manual->print();  // Bad data, since BlackBox free'd
    delete manual;    // Pair new and delete, but this is a double delete

    // Edit: use auto-duration and give them a pointer
    ComplexObj by_ref(3);
    BlackBox obj3 = BlackBox(&by_ref);  // they can't call delete on the pointer they have
    obj3.print_data();
    by_ref.print();

    // Use a shared pointer
    std::shared_ptr<ComplexObj> our_ptr(new ComplexObj(4));
    BlackBox obj4 = BlackBox(our_ptr.get());
    obj4.print_data();
    our_ptr->print();  // Bad data, they have free'd
    // double delete when our_ptr goes out of scope

    return 0;
}

คำถามอื่น ๆ ที่ฉันอ่านเกี่ยวข้องกับหัวข้อนี้...


person Jay    schedule 08.01.2021    source แหล่งที่มา
comment
ทำไมต้องเดา? อ่านคู่มือสำหรับไลบรารีเพื่อดูว่าจะลบพอยน์เตอร์หรือไม่   -  person HolyBlackCat    schedule 08.01.2021
comment
ให้ข้อมูลอ้างอิงแก่พวกเขา - รหัสของพวกเขาจะผิดพลาดหากพวกเขาเรียกลบ - ไม่แน่ใจว่าคุณหมายถึงอะไรที่นี่ หากฟังก์ชันคาดว่าจะมีตัวชี้ คุณจะไม่สามารถผ่านการอ้างอิงได้ ใน BlackBox obj3 = BlackBox(&by_ref); &ref ไม่ใช่ข้อมูลอ้างอิง แต่ใช้ ที่อยู่ของ ref   -  person churill    schedule 08.01.2021
comment
อ่านเอกสารของพวกเขา หากพวกเขาบอกว่าเป็นเจ้าของพอยน์เตอร์ คุณก็รู้ว่าคุณไม่จำเป็นต้องลบมัน หากพวกเขาไม่พูดอะไร ก็ถือว่าคุณต้องทำความสะอาดมัน หากพวกเขาไม่ได้จัดทำเอกสารอย่างถูกต้องจนทำให้หน่วยความจำรั่วหรือถูกลบสองครั้ง ให้บ่นกับพวกเขาเสียงดัง   -  person TheUndeadFish    schedule 08.01.2021


คำตอบ (1)


คุณไม่สามารถแก้ไขปัญหานี้ด้วยข้อมูลที่คุณมี ทางเลือกทั้งหมดทำให้เกิดขยะ

คุณต้องอ่านเอกสารประกอบของ API ที่คุณใช้

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

ชีวิตบางครั้งก็ห่วย

หากคุณมี API ที่เสียหายหรือเป็นศัตรู สิ่งเดียวที่ปลอดภัยเพียงครึ่งทางที่ต้องทำคือการโต้ตอบกับ API ในกระบวนการที่แยกจากกัน ล้างการสื่อสารทั้งหมดอย่างระมัดระวัง และปิดกระบวนการ

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

หาก API นี้เป็นแบบภายในและคุณมีสิทธิ์ควบคุม ให้พยายามทำให้อาร์กิวเมนต์ของพอยน์เตอร์ที่เป็นเจ้าของทั้งหมดเป็น std::unique_ptr<>s นั่นทำให้ชัดเจนใน API ว่าคุณตั้งใจจะเป็นเจ้าของออบเจ็กต์และลบออกในภายหลัง

person Yakk - Adam Nevraumont    schedule 08.01.2021