vs2005里auto_ptr的指针赋值一个陷阱

先来一段代码:

#include <memory>
#include <atlbase.h>

class A
{
public:
	A() : ma(0) {}
	void print() {
		ATLTRACE(_T("%d"), ma);
	}
private:
	int ma;
};

int _tmain(int argc, _TCHAR* argv[])
{
	std::auto_ptr<A> aPtr = new A();
	aPtr->print();
	return 0;
}
Debug运行这段代码的时候,直接报错,提示aPtr不可以解引用。

看了好几遍,感觉好像没什么问题,找不到头绪。 没办法,一步步的跟进去调试看到底在哪里出的事。

跟到auto_ptr的构造函数,才发现它调用的构造函数不对,上述代码调用的构造函数如下:

	auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()
		{	// construct by assuming pointer from _Right auto_ptr_ref
		_Ty **_Pptr = (_Ty **)_Right._Ref;
		_Ty *_Ptr = *_Pptr;
		*_Pptr = 0;	// release old
		_Myptr = _Ptr;	// reset this
		}
auto_ptr_ref是一个proxy类,它接受void*类型的指针参数,代码如下:

template<class _Ty>
	struct auto_ptr_ref
		{	// proxy reference for auto_ptr copying
	auto_ptr_ref(void *_Right)
		: _Ref(_Right)
		{	// construct from generic pointer to auto_ptr ptr
		}

	void *_Ref;	// generic pointer to auto_ptr ptr
	};

这说明,new运算符返回的指针类型是个void*,问题极有可能出上述auto_ptr构造函数里面。

auto_ptr_ref的_Ref持有了new出对象的指针,而在上述auto_ptr构造函数中,把它当作了A**来使用,并解引用了一次来获取A*。

很明显,这一次解引用导致auto_ptr中指针取到的值是0。

同时,下面的代码也没有调用到正确的构造函数,它调用的构造函数跟上面的是一样的:

	A a;
	std::auto_ptr<A> aPtr = &a;
	aPtr->print();

auto_ptr的指针转换构造函数带了explicit关键字,除非写成 aPtr(&a)。可以用下面的例子说明这两者之间的区别:

class B
{
public:
	explicit B(A* pa) : ma(pa) { }
	B(void* p) : ma(0) {}

private:
	A* ma;
};
int _tmain(int argc, _TCHAR* argv[])
{
	A a;
	B b = &a;
	return 0;
}
上面调用的是B(void*)这个构造函数,如果把explicit去掉,调用的是B(A*)这个构造函数。




你可能感兴趣的:(C++,auto_ptr)