一个类怎么知道它不应该在析构函数中释放它分配的内存?因为类是指向指针的指针?
一些不能工作的示例代码(未经测试的)。问题在MyOtherClass
的构造函数
class MyClass {
~MyClass() { free(...); } // free some vars, does not matter what.
};
class MyOtherClass {
MyClass *m_ptr;
MyOtherClass(MyClass pointee) {
m_ptr = &pointee;
// when this constructor is finished, the destructor of parameter "pointee" will be called.
// and therefore the attribute "m_ptr" points to nothing.
}
};
MyClass
有可能使用这样的东西吗?
class MyClass {
bool i_am_a_pointee = false; // but how and where to assign this?
~MyClass() {
if (!i_am_a_pointee) { free(...); }
}
};
目标是为多个不同的类创建一个类似容器的类。
代码:
class MyClassA {
MyClassA() {}
// here the pointer is cleared because that is required for my class.
// So when the var goes out of scope like in the constructor of "MyContainer(MyClassB)" all the vars will be deleted and therefore the pointer technically points to nothing.
~MyClassA() { free(...); }
};
class MyClassB {
MyClassB() {}
// here the pointer is cleared because that is required for my class.
// So when the var goes out of scope like in the constructor of "MyContainer(MyClassB)" all the vars will be deleted and therefore the pointer technically points to nothing.
~MyClassB() { free(...); }
};
class MyContainer {
MyClassA *m_class_a;
MyClassB *m_class_b;
MyContainer(MyClassA x) {
m_class_a = &x // here the problem.
}
operator MyClassA() {
return *m_class_a;
}
MyContainer(MyClassB x) {
m_class_b = &x // here the problem.
}
operator MyClassB() {
return *m_class_b;
}
};
int main() {
MyContainer container;
MyClassA a;
MyClassB b;
container = a; // here the pointer is empty because of the problem.
MyClassA a1 = container;
container = b;
MyClassB = container;
}
MyOtherClass(MyClass pointee) {
m_ptr = &pointee;
}
MyContainer(MyClassA x) {
m_class_a = &x // here the problem.
}
这里你取pointee
/x
的值,这意味着编译器会做一个拷贝。你需要定义一个有意义的复制构造函数来处理指针。
然后你把参数的地址,这是一个本地堆栈变量。在函数结束时,变量消失了,指针悬空了。无论你如何正确地实现MyClassA
,这都不会起作用。
需要一个指针或引用,这样就可以从调用者而不是局部变量那里获得对象的地址。我建议使用智能指针。
永远不要存储原始指针。有太多的方法可以把它搞砸。当一个类是指针的唯一所有者时,使用unique_ptr
。当您需要将指针存储在多个位置时,请使用shared_ptr
。如果不确定,比如当返回一个用户可能存储也可能不存储的指针时,默认为shared_ptr
。
除了避免错误,这也简化了你的代码。通常不需要析构函数,因为unique_ptr
/shared_ptr
会为您处理清理工作。
一个类怎么知道它不应该释放它在析构函数。因为类是指向指针的指针?
简短的回答是,如果你想持有一个可能是也可能不是拥有指针的原始指针,那么你需要以某种方式跟踪该信息。作为一种粗略的方法,您可以有一个名为delete_pointer_in_destructor
的布尔成员变量,如果指针应该在析构函数中删除,则将其设置为true,如果不应该删除,则将其设置为false。如果对象是在程序的其他地方分配的,那么调用代码可能必须将这个布尔值作为参数(以及指针)传递给代码,以告诉代码它需要做什么,因为您的代码无法仅从原始指针中知道哪种设置是合适的。
一个更好和更少出错的方法,OTOH,将完全避免生owning-pointers——只存储对象按值(在这种情况下你不需要调用new
或者delete
),或(如果你不能这样做,如因为你需要多态行为)然后至少使用智能指针std::shared_ptr
或std::unique_ptr
时他们会处理所有的决定(或者)调用删除你,,让你得到这些决策错误的风险。
MyOtherClass(MyClass pointee) {
m_ptr = &pointee;
// when this constructor is finished, the destructor of parameter "pointee" will be called.
// and therefore the attribute "m_ptr" points to nothing.
}
你应该尽量避免在对象被销毁后仍然保留指向该对象的指针;持有悬浮指针是无用的,而且是自找麻烦,因为任何实际使用悬浮指针的尝试都会调用未定义的行为。因此,对上述代码的修复将是在构造函数末尾将m_ptr
设置为NULL(或者更好的是,一开始就不将其设置为&pointee
)