Что дать функции, которая ожидает необработанный указатель?

Я использую библиотеку, которая для создания некоторого объекта, который я использую, ожидает необработанный указатель на объект. Я не уверен, что он будет делать с указателем, чтобы сделать мой код максимально безопасным, что я должен передать этой функции?

  1. Используйте уникальный указатель — если они решат удалить указатель, я сделаю двойное удаление
  2. Следите за необработанным указателем - плохо, потому что я должен помнить, чтобы написать удаление, но это все еще может быть двойное удаление
  3. Используйте автоматическую продолжительность и дайте им указатель Дайте им ссылку — их код выдаст ошибку, если они вызовут удаление
  4. Используйте общий указатель - та же проблема двойного удаления, что и уникальный указатель, но теперь моя область не повредит их указателю

Судя по моему чтению, вариант 3 похож на то, что я должен сделать - они не должны вызывать удаление для указателя, и этот формат обеспечивает это. Но что, если я не знаю, вызовут ли они сейчас или в будущем удаление по ссылке, которую я им дал? Использовать общий указатель и сказать, что я не виноват в двойном удалении?

#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 без знания этого является распространенной ошибкой начинающих программистов на C++. Не делай этого. Да, это отстой.

Если этот API вообще внутренний и у вас есть какой-либо контроль, постарайтесь сделать все аргументы указателя владельца равными std::unique_ptr<>s. Это дает понять API, что вы намерены владеть объектом и удалить его позже.

person Yakk - Adam Nevraumont    schedule 08.01.2021