问题描述
我正在使用一个库,为了构造我使用的某个对象,需要一个指向对象的原始指针。我不确定它会用指针做什么,为了使我的代码尽可能安全,我应该向这个函数传递什么?
- 使用唯一的指针 - 如果他们决定删除指针,我将进行双重删除
- 跟踪原始指针 - 不好,因为我必须记住写删除,但它仍然可能是双重删除
- 使用自动持续时间并给他们一个指针
给他们一个引用- 如果他们调用 delete,他们的代码会出错 - 使用共享指针 - 与唯一指针相同的双重删除问题,但现在我的作用域不会损坏它们的指针
根据我的阅读,选项 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;
}
我阅读过的与此主题相关的其他问题...
- unique_ptr.get() is legit at times
- I should pass by reference
- I think I am case 2 and should pass by reference
解决方法
你不能用你所拥有的信息来解决这个问题。所有的选择都会产生垃圾。
您必须阅读您正在使用的 API 的文档。
在不知道他们是否拥有指针所有权的情况下执行 4 个答案中的任何一个都会导致问题。
生活有时很糟糕。
如果您有一个损坏或恶意的 API,唯一安全的方法是在一个单独的进程中与其交互,小心地刷新所有通信,然后关闭该进程。
如果 API 没有损坏或恶意,您应该能够知道它是否获得了指向对象的所有权。在不知道这一点的情况下调用 API 是 C++ 新手程序员常见的错误。不要这样做。是的,这很糟糕。
如果这个 API 完全是内部的并且您有任何控制权,请设法使所有“拥有指针”参数都为 std::unique_ptr<>
。这在 API 中明确表示您打算拥有该对象并稍后将其删除。