空指针的成员函数调用

转载自:http://hi.baidu.com/sangwf/blog/item/0be10af482d0c46edcc47464.html

 

我一直认为技术是没有止境的,不管你怎么去学,总有你没有掌握的地方。但是,人,是不能停下脚步的。

 

    今天在检查一个MFC程序,看到GetSafeHwnd函数,于是让我想明白到底它比m_hWnd成员变量safe在哪里?到网上查了一下资料,发现了GetSafeHwnd的实现:

_AFXWIN_INLINE HWND CWnd::GetSafeHwnd() const {
           return this == NULL?NULL:m_hWnd;
}

    开始一看感觉不会吧?这有意义么?this为NULL了,函数还能调用吗?于是写了一个简单的程序来做测试,代码如下:

 

class A {
public:
     int i;
     void f()  {
         cout<<"Hello"<<endl;
     }
};


void main() {
     A * p= NULL;
     p->f();
}

    测试发现,程序能够正常运行。把p赋一个非空值如p=(A*)123; 同样如此。于是想搞明白这到底是怎么一回事。虽然以前明白类成员函数中其实是隐藏了一个this指针,但不同的实例在调用函数时是如何工作的,还不是很清楚。通过这个测试,才能我彻底明白。

    对于一个类,在编译好的汇编代码中,只有一份代码拷贝,但是有不同的实例空间。比如我们定义A a,b;我们调用a.f()和b.f()时,会跳转到类代码中f()函数的实现部分。

    但如果你要引用成员变量,比如a.i,那么程序需要找到a在内存中的地址,然后通过便宜量找到成员i的地址。如果f()中加上一句cout<<i<<endl的话,上面的代码很显然会崩溃,为什么呢?

    在函数的汇编代码中,有一个变量this,你在做函数类的函数调用的时候,类似与函数参数一样压到栈上去,虽然不同实例执行了同一段代码,因为this不同,得到的结果当然不同。如果你要存取成员变量,而this是一个非法地址,当然会引起崩溃。

 

    综上可知,即时一个函数调用正常,还不能确定指针非空,很可能是因为成员函数中没有使用成员变量的缘故。看来,这还真是一个搞笑的bug。

 

 

 

这是我自己的一段代码:

int _tmain(int argc, _TCHAR* argv[])
{
   
string leftString("test ");
   
string rightString("test");
    dstring
*praxis = new dstring();   

    praxis
->praxis1(leftString, rightString);
    delete praxis;
    praxis
= NULL;
    

    cout << praxis->praxis2() <<endl;
    

    system(
"pause");
   
return 0;
}

delete释放了praxis所指向的堆地址中的数据,并且指针被赋为空了, 当调用praxis->praxis2()时,虽然这个时候praxis指针已经空了,但由于Praxis2方法中没有使用成员变量,所以,程序并没有试图去访问堆,也就不会引起error或者将系统搞崩溃。

下面是全部的代码:

// dstring.h
//
#ifndef DSTRING_H
#define DSTRING_H
#pragma once

#include
<string>
using namespace std;
class dstring
{

public:
    dstring(
void);
   
void praxis1(const std::string &leftStr, const std::string &rightStr); string praxis2(void);
   
string praxis3(void);

public:
   
~dstring(void);
};
#endif

// dstring.cpp
//

#include
"StdAfx.h"
#include
"dstring.h"
#include
<string>
#include
<stdio.h>
#include
<iostream>
#include
<cctype> dstring::dstring(void)
{
}

dstring::
~dstring(void)
{
}

void dstring::praxis1(const string &leftStr, const string &rightStr)
{
   
if (leftStr == rightStr)
    {
        cout
<<leftStr<<" and "<<rightStr<<"is equal"<<endl;
    }
   
else
    {
       
if (leftStr > rightStr)
        {
            cout
<<leftStr<<" is bigger than "<<rightStr<<endl;
        }
       
else
        {
            cout
<<leftStr<<" is smaller than "<<rightStr<<endl;
        }
    }
}


string dstring::praxis2(void)
{
   
string sentence, article;
   
bool firstEnter = true;

    cout
<< " Please enter sentences and end with Ctrl + Z." << endl;
   
while (cin >> sentence)
    {   
       
if (!firstEnter)
        {
            sentence
= " " + sentence;
        }
        article
+= sentence;
        firstEnter
= false;
    }
   
return article;
}


string dstring::praxis3(void)
{
   
string sentence, article;
   
    cout
<< "Please enter a sentence with punctuatio." <<endl;
   
//cin >> sentence;
   
   
while (cin >> sentence)
    {
        article
+= sentence;
    }

   
for (string::size_type index = 0; index != article.size(); index ++)
    {
       
if (ispunct(article[index]))
        {
            article[index]
= ' ';
        }
    }
   
return article;
}

你可能感兴趣的:(String,汇编,测试,null,delete,mfc)