ATL (Active Template Library) version 14.00のATL::CComHeapPtr<T>
は譲渡非対応です。関数の戻り値に指定すると通常はコピーコンストラクタが存在しないのでコンパイルエラーが発生しますが、なぜかエラーが発生せずに保持するメモリを解放してダングリングポインタを持つコピーを返すことがありました。
同じATLクラス、それもATL::CComHeapPtr<T>
の基底クラスであるATL::CHeapPtr<T>
は非const参照のコピーコンストラクタによる譲渡を実装しているため気づくまで時間がかかりました。
現状のATL::CComHeapPtr<T>
はバグの原因となるため、非const参照のコピーコンストラクタおよびムーブコンストラクタを実装した次のCComHeapPtr2<T>
の使用を推奨します。
# include <atlbase.h>
using namespace ATL;
// CComHeapPtrに非const参照のコピーコンストラクタとムーブコンストラクタを追加したクラス
template <typename T>
class CComHeapPtr2 :
public CHeapPtr<T, CComAllocator>
{
public:
CComHeapPtr2() throw()
{
}
explicit CComHeapPtr2(T* pData) throw()
: CHeapPtr<T, CComAllocator>(pData)
{
}
CComHeapPtr2(CComHeapPtr2& p)
: CHeapPtr<T, CComAllocator>(p)
{
}
CComHeapPtr2(CComHeapPtr2&& p)
: CHeapPtr<T, CComAllocator>(p)
{
}
};
- ムーブコンストラクタがない場合、STLコンテナクラス(
std::vector
やstd::list
)のpush_back
でconst参照のコピーコンストラクタが見つからずに想定外の動作が発生します(ないはずのconst参照のコピーコンストラクタが呼び出されてダングリングポインタが発生します)。push_back
はムーブコンストラクタに対応しているため、ムーブコンストラクタを定義すればstd::move
でそちらを呼び出せます。-
IShellFolder
のEnumObjects
で取得したLPITEMIDLIST
を管理するときに上記のバグが起こると大惨事です。
-