假设我们有以下内容:
//! SomeClass.hpp
class
{
public:
SomeClass( void );
~SomeClass( void )
{
delete mFoo;
delete mBar;
}
...
private:
Foo* mFoo;
Bar* mBar;
StackObj mStackFoo;
};
//! SomeClass.cpp
SomeClass::SomeClass( void )
{
mFoo = new Foo;
mBar = new Bar;
mStackFoo = StackObj( ... );
}
现在,当我们初始化指针时,我的理解是构造函数会创建 SomeClass 成员的不必要副本,因此只是为了分配内存而分配然后释放内存。
通常使用初始化列表,加上一个单独的初始化函数(用于堆分配的内存)作为避免这种情况的方法。SaySomeClass
有一个私有成员函数,定义为void initHeapMem( void )
. 那么我们可以这样做,
SomeClass::SomeClass( void )
: mFoo( NULL ),
mBar( NULL ),
mStackFoo( ... )
{
initHeapMem();
}
void SomeClass::initHeapMem( void )
{
mFoo = new Foo;
mBar = new Bar;
}
自然,这在一定程度上解决了问题。我认为这里的问题是仍然存在另一个正在执行的函数调用的开销。
我们不能对原始指针使用初始化列表的原因是它们不是线程安全的。如果出现问题,程序抛出异常,仍然会出现内存泄漏。注意:这是根据我所阅读的内容,如果这是错误的,我深表歉意。
因此,使用 boost/C++11,我们可以使用来自#include <tr1/memory>
头文件中指令的智能指针(假设我们使用的是 STL)。
如果我们要使用,例如std::unique_ptr< T >
,那么我们将拥有Bar* mBar
并Foo* mFoo
替换为:
std::unique_ptr< Foo > mFoo;
std::unique_ptr< Bar > mBar;
这将允许我们这样做,
SomeClass::SomeClass( void )
mFoo( new Foo ),
mBar( new Bar ),
mStackFoo( ... )
{
}
由于智能指针有效地将内存分配包装在自己的构造函数中。
虽然这是一个不错的解决方案,但我个人并不是对我创建的每个堆对象都使用智能指针的人,而且我知道 C++ 社区中的其他人也有同样的感受。
tl;博士
有了所有这些,我真正想知道的是,除了我上面列出的那些之外,是否有任何更有效的替代方法来初始化对象中的类成员(尤其是随着 C++11 的出现)。