当我在C++类中包装"原始"资源时,在析构函数代码中,我通常只是释放已分配的资源,而不关注其他步骤,如清零指针等.例如:
class File
{
public:
...
~File()
{
if (m_file != NULL)
fclose(m_file);
}
private:
FILE * m_file;
};
Run Code Online (Sandbox Code Playgroud)
我想知道这种代码风格是否包含潜在的错误:即是否可能不止一次调用析构函数?在这种情况下,在析构函数中正确的做法是清除指针以避免双重/多次破坏:
~File()
{
if (m_file != NULL)
{
fclose(m_file);
m_file = NULL; // avoid double destruction
}
}
Run Code Online (Sandbox Code Playgroud)
可以为堆分配的内存做一个类似的例子:if m_ptr是指向分配的内存的指针new[],下面的析构函数代码是OK吗?
// In destructor:
delete [] m_ptr;
Run Code Online (Sandbox Code Playgroud)
还是应该清除指针,以避免双重破坏?
// In destructor:
delete [] m_ptr;
m_ptr = NULL; // avoid double destruction
Run Code Online (Sandbox Code Playgroud) 我一直在寻找一种方法,以确保在所有情况下(例如在类构造函数末尾的异常)都清除类的成员变量。
因为它们是成员变量,所以“尝试,捕获”和“使用”模式没有用。我注意到.NET C ++(C ++ / clr:safe)提供了对智能指针(称为msclr :: auto_handle)的仿真,例如auto_ptr或shared_ptr。这非常有用,因为我可以非常干净地确定性地破坏有限资源,例如线程或套接字。
我一直在分析用C ++ / clr生成的IL,并注意到它实际上所做的就是在修改封装数据的每个函数中都通过try / faults向IL垃圾邮件。
我已经为有兴趣的人列出了IL清单。(try / fault不是我添加的,而是C ++ / clr编译器添加的)
MyClass()
{
myDisposable.reset(gcnew MyDisposable());
throw gcnew Exception("Hello World");
// myDisposable needs to clean up now
// because it is very large or locks a limited resource.
// Luckily with RAII.. it does!
}
Run Code Online (Sandbox Code Playgroud)
...变成...
.try
{
IL_0006: ldarg.0
IL_0007: ldloc.0
IL_0008: stfld class msclr.'auto_handle<MyDisposable>' modreq([mscorlib]System.Runtime.CompilerServices.IsByValue) MyClass::myDisposable
IL_000d: ldarg.0
IL_000e: call instance void [mscorlib]System.Object::.ctor()
IL_0013: ldarg.0
IL_0014: ldfld class msclr.'auto_handle<MyDisposable>' …Run Code Online (Sandbox Code Playgroud) #define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
struct A
{
A(char* p)
: p(p)
{}
~A()
{
delete this->p;
}
char* p;
};
int main()
{
A a(new char);
_CrtDumpMemoryLeaks();
}
Run Code Online (Sandbox Code Playgroud)
在调试模式下运行后,Visual Studio 2012的输出窗口显示:
Detected memory leaks!
Dumping objects ->
{142} normal block at 0x007395A8, 1 bytes long.
Data: < > CD
Object dump complete.
Run Code Online (Sandbox Code Playgroud)
原因是什么?
我现在正在学习 C++。这是一种非常复杂的语言,我不确定应该使用哪个功能以及何时使用。
C++ Primer 引入了 RAII 作为确保异常安全的方法。这是否意味着,作为一种良好的行为,当我想使用数组时,我应该将数组放入一个类中以分配和销毁资源。我知道我的想法很简单,或者说很幼稚。
我只是好奇什么是好的 C++ 编码行为。
unique_ptr<X> f()
{
unique_ptr<X> p(new X); // or {new X} but not = new X
// do something - maybe throw an exception
return p; // the ownership is transferred out of f()
}
Run Code Online (Sandbox Code Playgroud)
当异常抛出时,为什么我们关心对象X的存在,为什么我们关心它占用的内存呢?
处理异常后,该过程将很快终止,内存将被释放,为什么我们关心这个?
我想知道RAII是否总是在堆栈上分配,或者编译器是否曾将堆用于大型对象(然后可能会在堆栈中添加一个令牌作为提醒何时销毁相应的堆分配对象)?
更新:显然这个问题一直被认为不清楚.也许一个代码示例将使这更清楚:
在这段代码中:
void dosomething() {
MyClass myclass();
}
Run Code Online (Sandbox Code Playgroud)
假设编译器没有优化这样一个简单的例子,那么由此创建的MyClass实例是否总是在堆栈上分配,或者堆是否曾经使用过?
我想我现在理解了答案,这要归功于接受的答案 - 答案似乎是类实例本身在堆栈上,而其内容可能会或可能不会取决于它的构造函数是如何定义的.如果这不正确,请添加评论/答案.
为什么我们必须使用析构函数在c ++中取消分配内存,
我们可以使用
delete or delete[]
Run Code Online (Sandbox Code Playgroud)
程序终止时释放程序使用的所有内存是不正确的.
raii ×9
c++ ×7
exception ×2
.net ×1
c# ×1
c++11 ×1
destructor ×1
il ×1
memory ×1
memory-leaks ×1
objective-c ×1
visual-c++ ×1