如何在没有智能指针的情况下防止双重删除
How to prevent double delete without smart pointers?
也许这是一个愚蠢的问题,但我只是想确保不要把东西搞砸。假设我有这个结构:
struct Foo{
struct Bar { virtual int calc(int x) = 0; };
Bar* barX;
Bar* barY;
int x,y;
Foo(Bar* bx,Bar* by) : barX(by),barY(by) {}
void process(int xx,int yy){
x = barX->calc(xx);
y = barY->calc(yy);
}
~Foo();
};
struct IDBar : Foo::Bar { int calc(int x) { return x; } };
int main() {
IDBar* b = new IDBar();
Foo f = Foo(b,b);
Foo f2 = Foo(new IDBar(),new IDBar());
}
我不能使用 C++11(即没有智能指针),而且我不是 100% 确定......这是删除两个(或可能只有一个)Bar
对象的正确方法吗:
Foo::~Foo(){
if (barX == barY){ delete barX; }
else { delete barX; delete barY; }
}
?
PS:这个想法是Foo
拥有Bar
对象(因此将负责删除它们)。传递给构造函数的Bar
不应该用于其他任何用途。实际上,一个Bar
只能属于一个Foo
(我后来才意识到这个缺陷,但现在很好)。此外,Foo
不应该被复制(也许我应该明确防止这种情况)。
我和塔兹廷戈有一点分歧。对象获取传递给它的资源的所有权并非不合理。这发生在各种现实世界的代码中。记录了类获得传递给构造函数的资源的所有权的事实,仅此而已。如果有人在未查阅文档的情况下不当使用该类,他们就是在搬起石头砸自己的脚。
但是,这确实容易出错,我们希望捕获此类错误或防止它们发生。如果有某种方法可以保证没有其他人认为他们拥有资源,而Foo
这样做,我们就会走上正轨。在 C++11 中,这很容易使用 std::unique_ptr
.在早期C++标准中,有std::auto_ptr
.虽然早期的C++标准没有移动构造函数,但std::auto_ptr
的功能类似,即在分配或复制到新std::auto_ptr
时从旧std::auto_ptr
放弃资源。
我建议您使用 std::auto_ptr
.
如果显式允许为类的两个构造函数参数传入同一资源的情况Foo
,请创建一个仅接受一个std::auto_ptr<Bar>
的新构造函数。
最后,如果要使其无法复制Foo
,只需将复制构造函数和赋值运算符声明为私有运算符即可。
比较远非完美 - 想象一下你有三个指针。
为了确保永远不会发生双重delete
,你只打电话delete
一个怎么样?考虑以下场景:
- 分配
- 一个内存池(假设足以分配一千个对象)。这应该通过常规
new
调用在堆上分配,在新PoolAllocator<T>
类中的某个地方分配,并在其 desctructor 中delete
。 - 实现池,使其支持返回内存以供
T
使用的函数void* getMemory<T>()
,并推进内部指针。 - 确保无论调用什么
T
,都只能通过在池提供的内存上放置 new 来创建。
最后,您不必担心内存 - pool 对象可以是常规堆栈变量,堆上有内部结构。
否则,是什么禁止你实现自己的原型智能指针?
no. god no
Foo::~Foo(){
if (barX == barY){ delete barX; }
else { delete barX; delete barY; }
}
删除对象未自行分配的内存是非常危险的。拥有这些对象的任何内容都应删除它们。在您的情况下,main 应该负责删除那些分配的对象。
int main() {
IDBar* b = new IDBar();
IDBar* b2 = new IDBar();
IDBar* b3 = new IDBar();
Foo f = Foo(b,b);
Foo f2 = Foo(b2,b3);
delete b;
delete b2;
delete b3;
}
处理内存管理的对象本身的一个完美示例是 LinkedList。LinkedList 在其自身内部创建节点。用户对它们一无所知,而只是插入 T。然后,链接列表将在删除时删除它们。用户只负责删除链接列表,因为他或她创建了它。
std::list<MyObject*> list;
MyObject* object = new MyObject;
list.push_back(object);
//The list isn't going to delete object because it doesn't own it
delete object;
如果你坚持你的建筑,不能听从塔兹廷戈的设计规则;那么答案是肯定的:这是正确的方法!
然后为类 Foo 及其构造函数制作一个强大的 API 文档,从而接管对象 Bar 的终身责任。
- 如何在不强制转换每个参数的情况下删除初始值设定项列表中从 int 到 char 的缩小转换?
- 类(可能是代理)的命名,允许在不修改基础容器的情况下对项目进行排序和删除
- 在不使用任何 STL 容器的情况下删除重复项
- 如何在不泄漏内存的情况下删除链接列表
- 使用QT,如何在不读取整个文件的情况下删除文本文件中的第一行
- C++ 如何在不丢失内存的情况下删除节点
- 如何在没有递归的情况下删除链接列表
- 在只给定单个链接列表中间的节点的情况下删除该节点.C++
- 在不使用虚拟析构函数的情况下删除继承的对象时中止
- 检查目录树是否可以在不实际开始删除的情况下删除
- 如何在不知道其类型的情况下删除结构
- C++ 在不知道位置的情况下删除矢量中的特定值
- 如何在不导入任何库的情况下删除矢量
- 重写类运算符new并在不更改类的情况下删除
- 如何在无权访问的情况下删除对象
- 我将如何在不损坏列表的情况下删除链表中的节点
- Qmake:如何在不更改Qmake .conf的情况下删除某个项目的编译器标志
- 我可以在不检查是否存储该对象的情况下删除联合组件吗?
- 内存管理 - 是否可以在不调用析构函数的情况下删除 c++ 中的对象
- 我可以在不中断代码的情况下删除此警告吗?