[英]How can a class know, that it should not free its allocated memory in the destructor. Because the class is a pointee to a pointer?
一个类如何知道它不应该在析构函数中释放其分配的内存。 因为类是指针的指针?
一些不起作用的示例代码(未经测试)。 问题出在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 更好且更不容易出错的方法是完全避免原始拥有指针 - 仅按值存储对象(在这种情况下,您根本不需要调用new
或delete
),或者(如果你不能这样做,例如因为你需要多态行为)那么至少使用像std::shared_ptr
或std::unique_ptr
这样的智能指针,因为它们将处理关于何时(或是否)调用 delete 的所有决定您,并免除您做出错误决定的风险。
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
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.