介绍 QScopedPointer
原文出处:
http://labs.qt.nokia.com/2009/08/21/introducing-qscopedpointer/
by Harald Fernengel on August 21,2009
翻译:wangjieest
第一次翻译,请多见谅。
Qt usually takes the boring memory allocation and deallocation from you, either through its implicitly shared containers, or with QObject’s parent child relationship model.
But every once in a while, we need to allocate something on the heap, and then the stress starts – where do we delete it, and how do we make sure to not leak the memory?
通常Qt从C++开发者手里接管了枯燥无味的垃圾回收工作,例如通过Qt自身的隐式共享,或者用QObject父子关系模型。
但是,每一次我们需要在堆上分配内存的时候,就有压力了 —— 我们需要在哪儿删除它,我们如何确保不会有内存泄露?
To fix this problem, QScopedPointer was born.
It will delete the object it is pointing to automatically when it goes out of scope:
为了解决这个问题,QScopedPointer 诞生了。
当要超出作用域时,QScopedPointer 便会自动的删除它所指向的对象(的内存):
void foo()
{
QScopedPointer<int> i(newint(42));
//…
if (someCondition)
return;
// 我们在堆上分配的一个整数将在这个位置,
// …
} // 或者这个位置被自动的删除
A new exit condition in our function will not make it leak the integer that we allocated.
在我们函数中,一个新的出口条件,将会使我们分配的内存不会泄露!(真心不会翻)
So how do we access the object that we are pointing to?
QScopedPointer implements operator* and operator->, so you it can be accessed just like any other pointer:
那么,我们该如何访问和使用 QScopedPointer所指向的对象呢?
QScopedPointer已经实现了 operator * 和 operator ->操作符重载,所以,就像普通指针一样的去用它吧:
QScopedPointer<int> i(newint(42));
*i = 43;
Some operators are missing by design, for example the assignment operator:
一些常有的操作(操作符重载),在设计上是有意没有实现,例如 赋值运算符( = );
QScopedPointer<int> i(newint(42));
i = newint(43);// 错误
i.reset(new int(43)); // 正确
We figured that “reset” looks scary enough to make the reader realize that the old object is deleted, and the QScopedPointer is now pointing to the new object.
我们设想:"reset" 看起来足够吓人了,以致于能够使读者认识到,这样会删除旧的对象,并使QScopedPointer指向新的对象.
Another operator that is missing by design is the operator T*() that would allow accessing the pointer directly.This prevents accidents like:
另一个在设计时就没打算实现的操作符是 T*(),那将导致直接访问我们的指针而不是指针管理的对象。这是用来阻止如下的情况:
int*foo()
{
QScopedPointer<int> i(newint(42));
//…
return i; // thankfully, this does not compile.
}
Do you see the mistake?
The moment we return, our object will be deleted, because the scoped pointer goes out of scope.
We would return a dangling pointer, potentially leading to a nasty crash. However, we can tell QScopedPointer that its job is done and that we take ownership of the heap object by calling take(). Our function might look like this:
你有看到错误没?
在函数返回的同时,我们的对象会被删除,因为QscopedPointer离开其作用域了.
我们将会返回一个悬垂指针,有可能导致程序崩溃。然后,当我们可以通过调用take()成员函数,告诉QScopedPointer它的工作完成了,从而接手它所指向的堆的控制权,我们的函数可能会像如下这样:
int*foo()
{
QScopedPointer<int> i(newint(42));
…
if (someError)
return 0; // our integer is deleted here
return i.take(); // from now on, our heap object is on its own.
}
But what about memory allocated with malloc, or the operator new[] for arrays?
For those cases, we introduced a second template parameter to QScopedPointer that defines the cleanup:
但是如果是通过malloc分配的内存,或者通过 new[] 分配的数组呢?
对于这种情况,我们为QScopedPointer引进了第二个模板参数来定义其清理工作:
QScopedPointer<int, QScopedPointerPodDeleter> pod(static_cast<int*>(malloc(sizeofint)));
QScopedPointerPodDeleter (pod stands for “plain old data”) will call free on the object if our QScopedPointer goes out of scope.
For convenience, there is a QScopedArrayPointer that defaults to deleting the object it is pointing to with the delete[] operator.
It also features operator[] for convenience, so we can write:
当我们的QScopedPointer超出其作用域时,QScopedPointerPodDeleter(pod意为普通的旧数据(plain old data))将会为其指向的对象调用free()函数.
为方便起见,我们用一个QScopedArrayPointer来指向那些需要被delete[]删除的对象。
同样为了方便,它还具有operator [] 运算符重载(取数组成员) ,所以我们可以这样写:
void foo()
{
QScopedArrayPointer<int> i(newint[10]);
i[2] = 42;
…
return; // our integer array is now deleted using delete[]
}
Note that if you have a reference counted object, you can use QExplicitlySharedDataPointer to ensure that an object is deleted correctly when its reference count goes to 0.
注意:如果你需要管理那些采用了引用计数技术的对象,那么你可以使用 QExplicitlyShareDataPointer 来管理这些对象,让其在引用计数变为0时,保证对象的正确删除。
QScopedPointer and QExplicitlySharedDataPointer are already used all over the place in the Qt for S60 branch and will soon hit Qt’s master branch.
And the best part is that with the introduction of these smart pointers, we could remove lots of boring code and make Qt more readable without adding overhead – since all functions are inlined, the resulting binary using QScopedPointer is identical to the manual new/delete approach.
QScopedPointer 和 QExplicitlySharedDataPointer 已经被用于Qt开发S60分支的各个地方,很快的,它将进入Qt的主开发分支。
最大的亮点就是,Qt对这些智能指针的引入可使我们能够移除很多乏味的代码,并在不增加开销的情况下使Qt更具可读性——因为所有函数被内联实现的同时,在使用QScopedPointer管理内存而生成的二进制文件和手工new/delete方法是一样的.
Happy developing
用Qt的智能指针快乐的开发下去吧。