寻找C#和C ++的答案。 (在C#中,用'finalizer'replace'destructor')
我已经收到了一些C ++代码,其结构如下所示: typedef struct _someStruct_ { std::string someString; std::vector<std::string> someVectorOfStrings; int someOtherStuff; ~_someStruct_() { someString.clear(); someVectorOfStrings.clear(); } } someStruct; 这里的析构函数完全是多余的 – 如果结构被缺省的析构函数破坏,那么不会有任何string,向量等被破坏吗? 如果我编写代码,我不会想到在这里添加一个显式析构函数 – 我只是让编译器继续。 据我所知,唯一可能需要在结构中创build自己的析构函数的是,如果结构中的任何成员包含指向可能需要清理的数据的指针,或者是某些额外的function(例如debugging,一个结构被删除)是需要的。 我在这里错过了什么 – 有什么理由为什么string和向量已经在析构函数中明确清除? 我怀疑发送给我的人真的是C程序员(比如typedef),他试图把一些C代码转换成C ++。
我期望在这个程序中调用A::~A() ,但它不是: #include <iostream> struct A { ~A() { std::cout << "~A()" << std::endl; } }; void f() { A a; throw "spam"; } int main() { f(); } 但是,如果我改变最后一行 int main() try { f(); } catch (…) { throw; } 那么A::~A() 被调用。 我正在编译Visual Studio 2005中的“Microsoft(R)32位C / C ++ Optimizing Compiler Version 14.00.50727.762 for 80×86”。命令行是cl […]
我们在C ++中使用RAII的次数越多,发现自己的析构函数就越不重要。 现在,释放(最终确定,但是你想调用它)可能会失败,在这种情况下,exception确实是让楼上任何人知道我们的重新分配问题的唯一方法。 但是再一次,抛出析构函数是一个糟糕的主意,因为堆栈展开期间可能抛出exception。 std::uncaught_exception()可以让你知道什么时候发生了,但是除此之外,除了让你在终止之前logging消息之外,没有什么可以做的,除非你愿意让你的程序处于一个未定义的状态,有些东西被释放/定稿,有些则没有。 一种方法是有无抛出的析构函数。 但在很多情况下,这只是一个真正的错误。 例如,我们的析构函数可能会由于抛出一些exception而closures一些RAIIpipe理的数据库连接,而这些数据库连接可能无法closures。 这并不一定意味着我们可以在这个程序结束的时候继续。 另一方面,logging和追踪这些错误并不是每个案例的真正解决scheme, 否则我们就不需要例外了。 使用无抛析析构函数,我们也发现自己必须创build应该在破坏之前被调用的“reset()”函数,但是这只是打败了RAII的全部目的。 另一种方法就是让程序终止 ,因为这是你可以做的最可预测的事情。 有人build议链接exception,以便一次处理多个错误。 但是我真的从来没有真正看到过用C ++做的事情,我也不知道如何实现这样的事情。 所以它是RAII或例外。 不是吗? 我倾向于无耻的破坏者; 主要是因为它使事情变得简单(r)。 但我真的希望有一个更好的解决scheme,因为正如我所说的,我们使用RAII越多,我们就越发现自己使用的是不重要的东西。 附录 我添加链接到有趣的主题文章和我已经find的讨论: 投掷破坏者 关于SEH问题的 StackOverflow讨论 StackOverflow关于throwing-destructors的讨论(感谢,Martin York) 乔尔在例外 SEH被认为是有害的 CLRexception处理也涉及exception链接 草药Sutter对std :: uncaught_exception和为什么它没有你想象的那么有用 有关参与者的历史讨论 (长!) Stroustrup解释RAII Andrei Alexandrescu的范围卫队
我使用了一些UserControls ,它们在运行时在应用程序中创build和销毁(通过创build和closures内部具有这些控件的子窗口)。 这是一个WPF用户控件,并从System.Windows.Controls.UserControlinheritance。 没有可以覆盖的Dispose()方法。 PPMM是与我的应用程序相同的生命周期的Singleton 。 现在在我的(WPF) UserControl的构造函数中,我添加一个事件处理程序: public MyControl() { InitializeComponent(); // hook up to an event PPMM.FactorChanged += new ppmmEventHandler(PPMM_FactorChanged); } 我习惯于在析构函数中删除这样的事件处理程序: ~MyControl() { // hook off of the event PPMM.FactorChanged -= new ppmmEventHandler(PPMM_FactorChanged); } 今天我偶然发现,并想知道: 1)这是必要的吗? 还是GC照顾它? 2)这是否工作? 或者我将不得不存储新创build的ppmmEventHandler ? 我期待着你的回答。
我正在研究垃圾收集器如何在C#中工作。 我对使用Destructor , Dispose和Finalize方法感到困惑。 根据我的研究和理解,在我的类中有一个Destructor方法将告诉垃圾收集器以析构函数方法中提到的方式执行垃圾收集,这种方法不能在类的实例上显式调用。 Dispose方法是为了让用户控制垃圾收集。 Finalize方法释放类使用的资源,但不释放对象本身。 我不确定我是否正确地理解了这一点。 请澄清疑惑。 欢迎任何进一步的链接或指南。
我很好奇python中__del__的细节,什么时候以及为什么它应该被使用,什么不应该被使用。 我已经学会了这样一个艰难的方式,它不是真正的天真地期望从析构函数中得到什么,因为它不是__new__ / __init__的对立面。 class Foo(object): def __init__(self): self.bar = None def open(self): if self.bar != 'open': print 'opening the bar' self.bar = 'open' def close(self): if self.bar != 'closed': print 'closing the bar' self.bar = 'close' def __del__(self): self.close() if __name__ == '__main__': foo = Foo() foo.open() del foo import gc gc.collect() 我在文档中看到, 不保证__del__()方法在解释器退出时仍然存在的对象被调用。 […]
当你不得不在你的类中使用__destruct时,请给我一些真实的例子。
我在想:他们说如果你手动调用析构函数 – 你做错了什么。 但是情况总是如此吗? 有任何反驳吗? 情况需要手动调用,哪里难以避免?不可能/不可行/不切实际。
主要是C ++开发人员,Java和.NET中RAII(资源获取初始化)的缺失一直困扰着我。 清理的责任从类作者转移到它的消费者(通过try finally或.NET的using构造 )的事实似乎显着地低下。 我明白了为什么在Java中不支持RAII,因为所有的对象都位于堆上,垃圾收集器固有地不支持确定性破坏,但是在引入值types( struct )的.NET中,我们有(看似)RAII的完美人选。 在堆栈上创build的值types具有明确定义的范围,并且可以使用C ++析构函数语义。 但是,CLR不允许值types具有析构函数。 我的随机searchfind了一个说法,如果一个值types被装箱,它属于垃圾收集器的pipe辖范围,因此其销毁变得不确定。 我觉得这个论点还不够强,RAII的好处足以说明一个具有析构函数的值types不能被装箱(或用作类成员)。 长话短说我的问题是 :有什么其他的原因价值types不能用于引入RAII到.NET? (或者你认为我关于RAII显而易见的优势的观点是有缺陷的?) 编辑:由于前四个答案已经错过了这个观点,我一定没有清楚地expression这个问题。 我知道 Finalize及其非确定性特征,我知道using构造,我觉得这两个选项比RAII差。 using是一个类的消费者必须记住的另一件事(有多less人忘记把一个StreamReader放在一个using块?)。 我的问题是关于语言devise的一个哲学问题,为什么它是这样,可以改进? 例如,对于generics确定性可破坏的值types,我可以使using和lock关键字是冗余的(可以通过库类实现): public struct Disposer<T> where T : IDisposable { T val; public Disposer(T t) { val = t; } public T Value { get { return val; } } ~Disposer() // Currently illegal { […]