love in C++, live on MFC

to get ready...

C++博客 首页 新随笔 联系 聚合 管理
  47 Posts :: 0 Stories :: 97 Comments :: 0 Trackbacks

#

关于GetBuffer/ReleaseBuffer,网上比较流行的一种说法是:如果你要直接修改CString的内部数据,就要调用GetBuffer/ReleaseBuffer.我也同意这样的表述.

下面是几个例子,主要是错误的例子,来加深理解.
1
CString strTest = "123";
char* p = strTest.GetBuffer(0
);
int i =
 atoi(p);
strTest.ReleaseBuffer();
这种用法当然没有错,但是我认为这里的GetBuffer/ReleaseBuffer是没有必要的,为什么呢?因为
int __cdecl atoi(const char *) 的参数是const char*,CString的内部数据肯定不会被修改的.
所以上面的代码可以直接写成
CString strTest = "123";
int i = atoi((LPCTSTR)strTest);
顺便说一下GetBuffer的参数问题,网上的例子中,很多都是GetBuffer(5) GetBuffer(10)这样的常数,实际中的程序不可能是这么容易事先知道的,所以也就有了strTest.GetBuffer(strTest.GetLength() )的写法.其实,GetBuffer(0)就可以了.可以由GetBuffer的源码得到验证.

2
    CString strTest = "123 45";

    
//some other code

    CString strTest2 = strTest;
    
char seps[] = " "
;
    
char* pToken = 0
;
    
//char* pStr = strTest2.GetBuffer(0);

    pToken = strtok((char*)(LPCTSTR)strTest2, seps);
    //pToken = strtok(pStr, seps);
    
while
(pToken)
        pToken 
=
 strtok(NULL, seps);
         //strTest2.ReleaseBuffer(0);
运行上面的代码,可以看到strTest的值也变了,呵呵,这就是程序中一些关与CString的奇怪问题的起源.如果用注释中的GetBuffer/ReleaseBuffer方法,就一点问题也没有了.
同样,对于ReleaseBuffer的参数,缺省的是-1,但是我不建议.因为-1表示使用当前的00结束符位置来确定新的长度.而上面的例子中,strtok是会重新设置00结束符的,所以,安全的做法,就是把这个CString的长度设为0,ReleaseBuffer(0),反正它的内容已经变了,也没有人要用了.
说明一下,GetBuffer/ReleaseBuffer方法只能保证strTest不变,strTest2还是会变的.所以,对于一个成员变量,比如m_strTest2调用ReleaseBuffer要多一个心眼,局部变量就不用想这么多了.
那么怎么从最开始就意识到程序写错了呢?上面代码中(char*)(LPCTSTR)是很危险的,把const去掉了,否则strtok是编译不过的,也从一个侧面说明了const的重要性.
posted @ 2006-03-21 17:51 flyingxu 阅读(9907) | 评论 (6)编辑 收藏

http://www.cpper.com/
那里论坛里的都是大牛,说的话我听不懂,插不上嘴。
posted @ 2006-03-07 21:45 flyingxu 阅读(482) | 评论 (0)编辑 收藏

在《工作中发现的 》中,提到析构函数可以自己调用,并用一个例子编译、运行证明了。
现在有个问题,除了知道“析构函数可以自己调用”外,那么什么时候必须显式调用析构函数?

先看一段现实生活中的代码吧,mfc源码中:
BOOL CStatusBar::AllocElements(int nElements, int cbElement)
{
    
// destruct old elements
    AFX_STATUSPANE* pSBP = _GetPanePtr(0);
    
for (int i = 0; i < m_nCount; i++)
    {
        pSBP
->strText.~CString();   //注意看这里
        
++pSBP;
    }

    
// allocate new elements
    if (!CControlBar::AllocElements(nElements, cbElement))
        
return FALSE;

    
// construct new elements
    pSBP = _GetPanePtr(0);
    
for (i = 0; i < m_nCount; i++)
    {
        memcpy(
&pSBP->strText, &afxEmptyString, sizeof(CString));
        
++pSBP;
    }
    
return TRUE;
}
在上面的代码中,就有显式调用CString的析构函数的代码。cool。
因为还调用了CControlBar::AllocElements(),上面的代码不是很明显,我把CControlBar::AllocElements简化一下后:
BOOL CStatusBar::AllocElements(int nElements, int cbElement)
{
    
// destruct old elements
    AFX_STATUSPANE* pSBP = _GetPanePtr(0);
    
for (int i = 0; i < m_nCount; i++)
    {
        pSBP
->strText.~CString();   //注意看这里
        ++pSBP;
    }

    
// allocate new elements
    
//if (!CControlBar::AllocElements(nElements, cbElement))
    
//    return FALSE;
    
//简化后的代码,实际运行肯定有问题,但是关键东西出来了
    free(pSBP);//注意这里调用的是free
    pSBP = calloc(nElements, cbElement);

    
// construct new elements
    pSBP = _GetPanePtr(0); //根据mfc的代码,可以理解这里的pSBP和前面的pSBP还是同一个地址
    for (i = 0; i < m_nCount; i++)
    {
        memcpy(
&pSBP->strText, &afxEmptyString, sizeof(CString));
        
++pSBP;
    }
    
return TRUE;
}
这个时候,如果注意到我特别注释的free函数调用,可能已经意识到了为什么要显式调用析构函数了。
如果还没有,那么可以问自己一个面试常规问题:delete和free有什么区别?答:delete会使析构函数被调用。
或者反过来说,free没有调用析构函数,那么怎么办?所以你必须自己显示调用析构函数

上面的这个例子可以这样抽象下,现在需要free掉一块内存,而那块内存中,还有一个类,类里面还有指针,(这里是CString)需要在析构函数中释放内存。因为用的是free,所以那个类的析构函数不会自动被调用,这个时候,就必须显式调用那个类的析构函数。

这个是不是很偏的问题呢?遇到了就看看,没有遇到过,也不会影响日常工作,哈。

另外继续问个面试问题,new和calloc的区别?哈,构造的函数的调用啊
所以,上面的代码用的calloc,就必须显示调用构造函数啊,在哪里呢?就是
memcpy(&pSBP->strText, &afxEmptyString, sizeof(CString));
和CString的构造函数比较下:
_AFX_INLINE CString::CString()
    { m_pchData 
= afxEmptyString.m_pchData; }
但是,为什么不就直接调用构造函数呢?我也不知道。详见dhong下面的评论。(dhong纠正了我的一个错误)

不过,下面的代码
        CString aStr;
        CString
* pStr = &aStr ;
        pStr
->CString();

是编译不过的。

 

posted @ 2006-03-04 00:35 flyingxu 阅读(11500) | 评论 (7)编辑 收藏

今天看java,提到这样一种变量命名形式:
CBox aBox;
也就是说,在命名一个没有太多实际意义的变量时,可以在前面加一个“a”。
呵呵,我觉得这种命名方法还是蛮好的,可能是我看书看的少,在c++的书中还没有看到过这样的写法推荐。
而在msdn中,常见的例子为:
CFileFind finder;
或者
CFile myFile;
呵呵,也是尽量写一个名词形式。

所以呢,新的写法可以写成
CFile aFile


细小的问题,不用钻牛角尖,好玩。
posted @ 2006-03-03 23:14 flyingxu 阅读(934) | 评论 (1)编辑 收藏

关于CString的两个问题
CString,string,char*的综合比较(一) 

1 CString的基类
在《比较》一文中,写到:
“CString(typedef CStringT<TCHAR, StrTraitMFC<TCHAR>> CString)为Visual C++中最常用的字符串类,继承自CSimpleStringT类,主要应用在MFC和ATL编程中,主要数据类型有char(应用于ANSI),wchar_t(unicode),TCHAR(ANSI与unicode均可);”
我第一感觉就是文章写错了,因为我看过CString的源码的啊:

struct CStringData
{
    
long nRefs;             // reference count

    int nDataLength;        // length of data (including terminator)
    int nAllocLength;       // length of allocation
    
// TCHAR data[nAllocLength]


    TCHAR
* data()           // TCHAR* to managed data
        return (TCHAR*)(this+1); }
}
;

class
 CString
{
public
:
//
 Constructors

    
// constructs empty CString

    CString();
    
// copy constructor

    CString(const CString& stringSrc);
    
// from a single character

    CString(TCHAR ch, int nRepeat = 1);
    
// from an ANSI string (converts to TCHAR)

    CString(LPCSTR lpsz);
    
// from a UNICODE string (converts to TCHAR)

    CString(LPCWSTR lpsz);
    
// subset of characters from an ANSI string (converts to TCHAR)

    CString(LPCSTR lpch, int nLength);
    
// subset of characters from a UNICODE string (converts to TCHAR)

    CString(LPCWSTR lpch, int nLength);
    
// from unsigned characters

    CString(const unsigned char* psz);

// Attributes & Operations

但是看文章的样子,也不像是粗制滥造的,心里很是疑惑。
后来再打开VC7的源码看,果然:

typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;

看来微软在不知不觉中做了这么大的变化。

2
“string是方便的,可以从几乎所有的字符串构造而来,包括CString和char*; 
 CString次之,可以从基本的一些字符串变量构造而来,包括char*等; ”
的确,如下的代码是可以编译的:

CString strTest = "test";
string sTest(strTest);

但是这是表明string比CString方便吗?
实际上,在string sTest(strTest);中有一个函数被调用,就是:

_AFX_INLINE CString::operator LPCTSTR() const
    { 
return m_pchData; }

然后才是string构造生成,这能说是string比CString方便吗?应该说是CString比string方便才好。
虽然可以用

CString strTest(sTest.c_str() );

来初始化CString,但是CString没有参数为string的构造函数,也是一个小小的遗憾,毕竟string是c++标准库的一部分了。

posted @ 2006-03-02 09:29 flyingxu 阅读(1922) | 评论 (6)编辑 收藏

当我在运行wizard,选到某一个类时,遇到了这个错误提示:
Parsing error : Expected "*/"
出错的代码如下
 
BEGIN_EVENTSINK_MAP(CMonitorView, CFormView)
    //{{AFX_EVENTSINK_MAP(CMonitorView)
    ON_EVENT(CMonitorView, IDC_REGVALUE,       
72    /* Leave Cell */,     OnLeaveCellRV, VTS_NONE)    
    //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
但是我看来看去没有问题.

后来找到最初的代码一对比,原来/* Leave Cell */中间有个空格, 是的wizard解析出错,去掉空格就好了.哈
posted @ 2006-02-17 13:16 flyingxu 阅读(4835) | 评论 (0)编辑 收藏

编译结束时总是有个消息提示框出来,
"the .plg file has been modified outside of the source editor. Do you want to reload it?"
点yes或者no都还是不行,总是出来

问题的答案在
http://www.codecomments.com/Debugger/message500008.html
也就是在菜单window->Close All



文章来源:http://blog.csdn.net/flyingxu/archive/2006/02/12/597392.aspx
posted @ 2006-02-13 01:49 flyingxu 阅读(1120) | 评论 (0)编辑 收藏

Code reviews are often misused and painful for everyone, but they don't have to be. Some simple steps can convert torture into teaching and improve the long-term outlook for code quality in your organization.
文章来源:http://blog.csdn.net/flyingxu/archive/2006/02/09/594974.aspx
posted @ 2006-02-09 18:08 flyingxu 阅读(91) | 评论 (0)编辑 收藏

class wizard出错与c++语法出错没有关系

class wizard根据//{{来寻找插入函数的入口,所以,如果//{{出现的次数有多次,就出错了.
需要注意的是,几时是被注释掉的代码,对class wizard也有影响,虽然编译能通过.

参见http://www.codeguru.com/forum/archive/index.php/t-112218.html
Check that you have only one of each of these in MyClass.h:

//{{AFX_DATA(CMyClass)
//{{AFX_VIRTUAL(CMyClass)
//{{AFX_MSG(CMyClass)

...and that you have only one of each of these in MyClass.cpp:
//{{AFX_DATA_INIT(CMyClass)
//{{AFX_DATA_MAP(CMyClass)
//{{AFX_MSG_MAP(CMyClass)


文章来源:http://blog.csdn.net/flyingxu/archive/2006/02/09/594960.aspx
posted @ 2006-02-09 17:56 flyingxu 阅读(2731) | 评论 (12)编辑 收藏

看了一篇blog文章“摘:VC编码规范 ”(http://blog.csdn.net/lts007007/archive/2006/01/05/571377.aspx),有几点意见:

函数名中用下划线,我觉得不好,ceate_point()我觉得可以写成CreatePoint(),这样的风格才是Windows API风格,我觉得可以借用。
反扩号的注释内容“}//end while(condition2)”我觉得完全多余,因为在VC环境中,可以用ctrl+]来定位括号之间的对应关系
对于局部变量,我觉得不用写l,如果一个变量不写g或者m,那么它就是局部变量

不知道那篇blog时作者原创还是转载,总的来说我觉得其中的VC规范不好(关于目录结构的还可以)。


文章来源:http://blog.csdn.net/flyingxu/archive/2006/01/08/573967.aspx
posted @ 2006-01-09 07:10 flyingxu 阅读(283) | 评论 (0)编辑 收藏

仅列出标题
共5页: 1 2 3 4 5