大多数人都说永远不会从析构函数中抛出异常 - 这样做会导致未定义的行为.Stroustrup指出"向量析构函数显式地为每个元素调用析构函数.这意味着如果元素析构函数抛出,向量破坏失败......实际上没有好的方法来防止从析构函数抛出的异常,所以库如果元素析构函数抛出",则不保证"(来自附录E3.2).
这篇文章似乎另有说法 - 抛出析构函数或多或少都没问题.
所以我的问题是 - 如果从析构函数抛出会导致未定义的行为,那么如何处理析构函数期间发生的错误?
如果在清理操作期间发生错误,您是否只是忽略它?如果它是一个可能在堆栈中处理但在析构函数中不正确的错误,那么从析构函数中抛出异常是否有意义?
显然,这类错误很少见,但可能.
您能否请C++开发人员详细介绍RAII是什么,为什么重要,以及它是否与其他语言有任何关联?
我做知道一点点.我相信它代表"资源获取是初始化".但是,这个名称并不符合我对RAII的理解(可能不正确):我得到的印象是RAII是一种初始化堆栈中对象的方式,当这些变量超出范围时,析构函数会自动被称为导致资源被清理.
那么为什么不称为"使用堆栈触发清理"(UTSTTC :)?你怎么从那里到"RAII"?
你怎么能在堆栈上创建一些东西来清理堆上的东西呢?此外,是否有不能使用RAII的情况?你有没有发现自己希望收集垃圾?至少一个垃圾收集器,你可以使用一些对象,同时让其他人管理?
谢谢.
想想一个返回必须为freed的东西的C函数,例如POSIX strdup().我想在C++ 11中使用该函数并避免任何泄漏,这是正确的方法吗?
#include <memory>
#include <iostream>
#include <string.h>
int main() {
char const* t { "Hi stackoverflow!" };
std::unique_ptr<char, void(*)(void*)>
t_copy { strdup(t), std::free };
std::cout << t_copy.get() << " <- this is the copy!" <<std::endl;
}
Run Code Online (Sandbox Code Playgroud)
假设它有意义,可以使用与非指针相似的模式吗?例如,POSIX的函数open返回int?
我注意到RAII在Stackoverflow上得到了很多关注,但在我的圈子里(主要是C++),RAII非常明显,就像问什么是类或析构函数一样.
所以我真的很好奇,如果那是因为我每天都被硬核C++程序员所包围,并且RAII一般不是众所周知的(包括C++),或者如果Stackoverflow上的所有这些问题都归因于事实我现在正在与没有使用C++成长的程序员联系,而在其他语言中,人们只是不使用/了解RAII?
我正在尝试编写一个基于Alexandrescu概念但使用c ++ 11习语的简单ScopeGuard.
namespace RAII
{
template< typename Lambda >
class ScopeGuard
{
mutable bool committed;
Lambda rollbackLambda;
public:
ScopeGuard( const Lambda& _l) : committed(false) , rollbackLambda(_l) {}
template< typename AdquireLambda >
ScopeGuard( const AdquireLambda& _al , const Lambda& _l) : committed(false) , rollbackLambda(_l)
{
_al();
}
~ScopeGuard()
{
if (!committed)
rollbackLambda();
}
inline void commit() const { committed = true; }
};
template< typename aLambda , typename rLambda>
const ScopeGuard< rLambda >& makeScopeGuard( const aLambda& …Run Code Online (Sandbox Code Playgroud) 我想finally在我的C++程序中实现一个块,如果不是原生设施,那么该语言肯定有工具可以实现.我想知道最好的方法是什么?
多年来一直在做Java,所以一直没有跟踪C++.已经最后条款中增加了C++异常处理的语言定义是什么?
是否有一种模仿Java的尝试/终极的青睐成语?
我还担心C++没有可能抛出的所有可能异常的最终超类型 - 比如Java的Throwable类.
我可以写:
try {
// do something
} catch(...) {
// alas, can't examine the exception
// can only do cleanup code and perhaps rethrow, ala:
throw;
}
Run Code Online (Sandbox Code Playgroud)
附录编辑:
我最终接受了得票最多的答案,即使用析构函数进行清理.当然,从我自己的评论来看,很明显我并不完全同意这一点.但是,C++就是这样,所以在我想到的应用程序中,我会或多或少地努力坚持共同的社区实践.我将使用模板类来包装尚未具有类析构函数的资源(即C库资源),从而赋予它们析构函数语义.
新的附加编辑:
嗯,而不是最后一个封闭功能或许?结合ScopeGuard方法的闭包(参见下面的答案之一)将是一种通过任意操作完成清理并访问清理代码的外部范围上下文的方法.清理可以用在Ruby编程中看到的成语方式来完成,它们在打开资源时提供清理块.C++不考虑关闭功能吗?
由于finally在C++中没有,你必须使用RAII设计模式,如果你希望你的代码是异常安全的.一种方法是使用像这样的本地类的析构函数:
void foo() {
struct Finally {
~Finally() { /* cleanup code */ }
} finalizer();
// ...code that might throw an exception...
}
Run Code Online (Sandbox Code Playgroud)
与直接解决方案相比,这是一个很大的优势,因为您不必编写清理代码2次:
try {
// ...code that might throw an exception...
// cleanup code (no exception)
} catch (...) {
// cleanup code (exception)
throw;
}
Run Code Online (Sandbox Code Playgroud)
本地类解决方案的一大缺点是您无法直接访问清理代码中的局部变量.因此,如果您需要访问它们,它会使您的代码膨胀很多,无论如何:
void foo() {
Task* task;
while (task = nextTask()) {
task->status = running;
struct Finally {
Task* task;
Finally(Task* task) : task(task) {}
~Finally() { task->status …Run Code Online (Sandbox Code Playgroud) 传统上,在C++中,您将在构造函数中创建任何依赖项,并在析构函数中删除它们.
class A
{
public:
A() { m_b = new B(); }
~A() { delete m_b; }
private:
B* m_b;
};
Run Code Online (Sandbox Code Playgroud)
这种技术/资源获取模式,它有一个共同的名称吗?
我很确定我已经在某处读过它但现在找不到它.
编辑:
正如许多人所指出的,这个类是不完整的,应该真正实现一个复制构造函数和赋值运算符.
最初,我故意将其遗漏,因为它与实际问题无关:模式的名称.但是,为了完整性和鼓励良好实践,接受的答案就是它.
我是C++的新手,来自C#.这是代码:
void function(int n)
{
double* array = new double[n];
//some work that can return or throw an exception
//...
delete[] array;
return;
}
Run Code Online (Sandbox Code Playgroud)
我知道usingC++中没有C#等价物.
有没有一种简单而优雅的方法来确保记忆将被释放?