通过传递外部指针或内部调用 new 构造的类,我可以在销毁时天真地删除这个指针吗?
Class constructed by passing an external pointer or by internally calling new, can I naively delete this pointer on destruction?
我有类A,它有一个指向B类的指针作为其字段之一:
class A {
private:
B *ptr;
public:
A(B*);
A();
~A();
}
A::A(B *ptr)
{
this->ptr = ptr;
}
A::A()
{
this->ptr = new B();
}
A::~A()
{
delete this->ptr;
}
我希望析构函数仅在 new 分配时才删除 B,我只能通过设置一个存储指针原点的标志来做到这一点(因此只有在构造 A 期间分配了 ptr 时才调用 delete),或者是否有更优雅的解决方案,即,我可以在任何指针上调用 delete(我知道如果传入的指针是使用 new 分配的, 它也将被删除,但如果指针是从调用 A 构造函数的作用域传入的,显然删除它是未定义的)?
更优雅的解决方案是不要拥有具有不同所有权模型的类,在这种情况下,拥有与不属于您的类。 不要将这两种想法混合在同一个类类型中,因为它只会混淆您的用户/客户端(通过违反最小意外原则)。
要么创建具有所需不同行为的单独类,要么选择一个所有权模型并强制客户端坚持使用它(要么在非默认构造函数中传入并转移所有权,要么不允许自我分配)。
还是有更优雅的解决方案
不,不是真的;需要清楚地记录谁拥有这个指针。 看起来你的班级是这样,所以你能自己构建ptr
吗?
#include <memory>
class A {
private:
std::unique_ptr<B> ptr;
public:
A(some_data args)
: ptr(new B(args)) { };
A();
}
如果你的类不拥有指针,那也没关系,只是不要释放它。 否则,您将需要在外部(即dealloc_on_destruct
)设置一个标志来知道该怎么做,这可能会变得混乱。
仅使用您提供的代码无法回答该问题。真正的问题是为什么你可以接受指针,如果指针传递给你,谁拥有内存。
根据对象在特定域中应执行的操作,可以采用不同的替代方法。例如,如果您可以与调用者共享所有权,那么您应该采取shared_ptr
,如果您将所有权保留在对象中,则应使用unique_ptr
在界面中明确表示您的对象将获取所有权。如果不共享所有权,请考虑传递对对象的引用(即使在内部存储指针),在这种情况下,您可以将所有权与实际使用分开:
// option 1: shared ownwership
class A {
std::shared_ptr<B> ptr;
public:
A( std::shared_ptr<B> const & p ) : ptr(p) {}
A() : ptr( std::make_shared<B>() ) {}
};
// option 2: grab ownership
class A {
std::unique_ptr<B> ptr;
public:
A( std::unique_ptr<B> p ) : ptr( std::move(p) ) {}
A() : ptr( new B(); }
};
// option 3: no ownership (unless we create the object)
// (separating concerns: ref to access the object, ptr to manage it)
class A {
std::unique_ptr<B> ptr; // only ownership
B * ref;
public:
A( B & b ) : ptr(), ref(&b) {}
A() : ptr( new B() ), ref(ptr.get()) {}
// Internally use 'ref' to access the object the destructor will delete it
// if needed
};
除了其他人所说的(避免这种设计):如果你绝对无法避免这种设计,并且你需要这个有趣的类,它有时拥有它的B
,有时不拥有,这取决于调用哪个构造函数,那么你可以像这样使用unique_ptr
(或shared_ptr
void delete_it(B*) { std::default_delete<B>()(t); }
void do_nothing(B *t) {}
class A {
unique_ptr<B, void(*)(B*)> ptr;
public:
A(B *ptr) ptr(ptr, do_nothing) {}
A() ptr(new B(), delete_it) {}
// no need for destructor
// hence also no need to worry about copy constructor or assignment
};
它比"原始指针加标志"更好的原因是,您不必实现删除器和副本(并在 C++11 中移动)。在性能方面,它可能比"原始指针加标志"更糟糕,但大多数时候你不需要担心这一点。如果合理的话,你可以回来做额外的工作。您无需更改类的源接口即可切换,尽管这可能会破坏二进制兼容性。
- 函数向量_指针有不同的原型,我可以构建一个吗
- 我可以制作指向智能指针的智能指针吗?
- 在C++中,如果我可以直接将整数分配给指针而不使用"new",为什么要使用"new"?
- 如果我在 const 函数上使用指针,我可以返回什么?
- 我可以有一个 ELI5 作为参考和指针以及何时使用它们吗?
- 我可以使用 decltype() 或其他东西通过指针获取真实类型吗?
- 我可以做些什么来改进指针向量中的此搜索?
- 如何将 c++ 类包装到 python 中,以便我可以使用 pybind11 访问其成员的公共方法(成员是一个对象指针)
- 如果我知道只会使用现有元素,我可以在数组开头之前传递指针吗?
- 我可以直接为指针分配地址吗?如果是,如何做到这一点
- 我可以在初始化之前使用 std::array 成员变量中的 data() 指针吗?发出警告
- 为什么我可以通过原始指针而不是shared_ptr来修改对象
- 为什么我可以通过野生指针调用成员函数
- 在C++我可以在不在本地声明结构的情况下将结构作为指针传递吗?
- 为什么我可以取消引用指向抽象类的指针?
- 我可以保证以负偏移访问指针吗?
- 我可以更改将引用参数传递到指针中并使其正常工作的函数的输入(C、C++)吗?
- 我可以从构造函数内传递会员函数指针吗?
- 为什么我可以更改指针的常数(const char *)槽的值
- 我可以依靠 initializer_list::const_iterator 是一个普通的指针吗?