也许这是一个愚蠢的问题,但我只是想确保不要弄乱东西。假设我有这个结构:
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
不应被复制(也许我应该明确地防止这种情况)。
答案 0 :(得分:1)
不不不不。上帝没有
Foo::~Foo(){
if (barX == barY){ delete barX; }
else { delete barX; delete barY; }
}
删除对象未自行分配的内存非常危险。无论拥有哪些对象都应删除它们。在你的情况下,主要应该负责删除那些分配的对象。
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.然后LinkedList将在删除时删除它们。用户只负责删除LinkedList,因为他或她创建了它。
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;
答案 1 :(得分:1)
如果你坚持你的建筑,不能听从Taztingo的设计规则;然后答案是肯定的:这是正确的方法!
然后制作类Foo及其构造函数的强大API文档,接管对象Bar的生命责任。
答案 2 :(得分:1)
我认为比较远非完美 - 只是想象你有三个指针。
为了确保永不发生双delete
,您只需拨打一个delete
怎么样?考虑一下情景:
new
调用在堆上分配,在新的PoolAllocator<T>
类中的某个位置,以及在其析构函数中的delete
。void* getMemory<T>()
返回要使用的T
内存,并推进内部指针。T
的任何内容只能通过池提供的内存中的新位置创建。最后,您不必担心内存 - 池对象可以是常规堆栈变量,堆上有内部。
否则,是什么禁止你实现自己的原型智能指针?
答案 3 :(得分:1)
我对Taztingo略有不同意见。对象获取传入其中的资源的所有权并非不合理。这种情况发生在各种现实世界的代码中。该类获取传递给构造函数的资源的所有权的事实被记录下来,就是这样。如果有人在没有查阅文件的情况下不正当地使用该课程,那么他们就会在脚下拍摄。
然而,这确实是容易出错的,我们希望捕获这些错误或阻止它们发生。如果有某种方法可以保证在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
无法复制,只需将复制构造函数和赋值运算符都声明为私有。