什么给一个需要原始指针的函数?

问题描述

我正在使用一个库,为了构造我使用的某个对象,需要一个指向对象的原始指针。我不确定它会用指针做什么,为了使我的代码尽可能安全,我应该向这个函数传递什么?

  1. 使用唯一的指针 - 如果他们决定删除指针,我将进行双重删除
  2. 跟踪原始指针 - 不好,因为我必须记住写删除,但它仍然可能是双重删除
  3. 使用自动持续时间并给他们一个指针 给他们一个引用 - 如果他们调用 delete,他们的代码会出错
  4. 使用共享指针 - 与唯一指针相同的双重删除问题,但现在我的作用域不会损坏它们的指针

根据我的阅读,选项 3 似乎是我应该做的 - 他们不应该在指针上调用 delete,而这种格式强制执行。但是,如果我不知道他们现在还是将来会在我给他们的参考资料上调用 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;
}

我阅读过的与此主题相关的其他问题...

解决方法

你不能用你所拥有的信息来解决这个问题。所有的选择都会产生垃圾。

您必须阅读您正在使用的 API 的文档。

在不知道他们是否拥有指针所有权的情况下执行 4 个答案中的任何一个都会导致问题。

生活有时很糟糕。

如果您有一个损坏或恶意的 API,唯一安全的方法是在一个单独的进程中与其交互,小心地刷新所有通信,然后关闭该进程。

如果 API 没有损坏或恶意,您应该能够知道它是否获得了指向对象的所有权。在不知道这一点的情况下调用 API 是 C++ 新手程序员常见的错误。不要这样做。是的,这很糟糕。

如果这个 API 完全是内部的并且您有任何控制权,请设法使所有“拥有指针”参数都为 std::unique_ptr<>。这在 API 中明确表示您打算拥有该对象并稍后将其删除。