先来一段代码:
#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 };
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*)这个构造函数。