
在这里,我使用一个程序作为本文的开始:
#include <iostream>
#include <conio.h>
class CTest
{
public:
int Func(int nNum);
private:
int m_nNum;
};
int CTest::Func(int nNum)
{
return nNum;
}
int main()
{
CTest* pTest = NULL;
CTest* pTest2;
CTest* pTest3 = new CTest;
delete pTest3;
std::cout << pTest->Func(10) <<
std::endl;
// 在 VS2003 下,应该注释此行再运行
std::cout << pTest2->Func(10) <<
std::endl;
std::cout << pTest3->Func(10) <<
std::endl;
system("PAUSE");
return 0;
}
读者可以在 MSVC6,VS2003,GCC 下测试本程序,除了 VS2003 下,需要注释"std::cout << pTest2->Func(10) << std::endl;"之外,程序都能正常运行。
我们可以得到这样一个结论,如果某成员函数没有访问成员变量,那么无论指针的值如何,对此成员函数的访问通常是有效的。
这种技巧被称之为奇技淫巧并不为过,不过云风有一文《更健壮的 C++ 对象生命期管理》谈及到它的用法(笔者对此持保留态度)。一般来说,我们是不会使用这种技巧的。我们来看看真实项目中的一个缩影:
// Thing
class CThing
{
public:
void Dosomething();
};
// Thing Manager
class CThingMgr
{
public:
// Check
bool Check(int nID);
// Remove
void Remove(int nID);
CThing* GetThing(int nID);
private:
std::map<int /*ID*/, CThing*>
m_mapThing;
};
bool CThingMgr::Check(int nID)
{
// Do something without variables
return true;
}
void CThingMgr::Remove(int nID)
{
std::map<int, CThing*>::iterator it =
m_mapThing.begin();
if (m_mapThing.end() == it)
return;
m_mapThing.erase(it);
}
使用:
CThing* pThing = mapThing->GetThing(nID);
// 做了很多事情之后
mapThing->Remove(nID);
// 又做了很多事情
pThing->Dosomething(); // 这里 pThing 已经被删除
我们可以看到,如果函数 Dosomething 没有访问 CThing 的成员变量,那么运行将很正常。假如某天,某个维护此代码的人员加入了一些访问成员变量的代码,那么程序将崩溃,并且这种错误非常难以发现(特别是维护人员和开发人员不是同一个人时)。
我们可以考虑使用一些技术来解决这个问题,在此笔者经过分析考虑认为使用智能指针来解决是最佳方案。
Powered by Haiwit