cstring和catlstring宁德catl和atl的区别别

2709人阅读
内存分配和管理(1)
C/C++(6)
最新的CString是使用模板技术来实现的,对于如我这样的模板小菜鸟而言,无疑是天书一般,即使顺藤也摸不到瓜。到底CString究竟是怎么一回事呢?经过许久的捉摸,终于一窥门径了。下面且听我娓娓道来。
CString被定义在atlstr.h文件中,如下:
#ifndef _ATL_CSTRING_NO_CRT
typedef CStringT& wchar_t, StrTraitATL& wchar_t,&wchar_t & & & CAtlStringW;
typedef CStringT& char, StrTraitATL& char, ChTraitsCRT&char & & & CAtlStringA;
typedef CStringT& TCHAR, StrTraitATL& TCHAR, ChTraitsCRT&TCHAR & & & CAtlS
#else&// _ATL_CSTRING_NO_CRT
typedef CStringT& wchar_t, StrTraitATL& wchar_t & &CAtlStringW;
typedef CStringT& char, StrTraitATL& char & &CAtlStringA;
typedef CStringT& TCHAR, StrTraitATL& TCHAR & &CAtlS
#endif&// _ATL_CSTRING_NO_CRT
#ifndef _AFX
typedef CAtlStringW CStringW;
typedef CAtlStringA CStringA;
typedef CAtlString CS
通过上面的代码,我们知道了CString其实是CAtlString的一个类型重定义,而CAtlString又分为CRT和非CRT版本。那为什么CString会是CAtlString的定义而不是直接被定义呢?这个问题的解答放在文章最后面的小故事里。
接下来看CStringT模板的定义:
template&typename BaseType, class StringTraits & class CStringT :&publicCSimpleStringT& BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck&BaseType,StringTraits&::c_bIsMFCDLLTraits &
原来CStringT继承于CSimpleStringT。那么就先去看看CSimpleStringT模板的定义。
template& typename BaseType , boolt_bMFCDLL = false& class CSimpleStringT
首先入眼的是一连串的定义:
&typedeftypename ChTraitsBase& BaseType &::XCHAR XCHAR;
&typedef typename ChTraitsBase& BaseType &::PXSTR PXSTR;
&typedef typename ChTraitsBase& BaseType &::PCXSTR PCXSTR;
&typedef typename ChTraitsBase& BaseType &::YCHAR YCHAR;
&typedef typename ChTraitsBase& BaseType &::PYSTR PYSTR;
&typedef typename ChTraitsBase& BaseType &::PCYSTR PCYSTR;
这些又是什么东东?!哦,看到ChTraitsBase模板了。
template&typename BaseType = char & //针对char的普通版本
class ChTraitsBase
&typedef char XCHAR;
&typedef LPSTR PXSTR;
&typedef LPCSTR PCXSTR;
&typedef wchar_t YCHAR;
&typedef LPWSTR PYSTR;
&typedef LPCWSTR PCYSTR;
template&&
class ChTraitsBase& wchar_t & // 针对wchar_t的特化版本
&typedef wchar_t XCHAR;
&typedef LPWSTR PXSTR;
&typedef LPCWSTR PCXSTR;
&typedef char YCHAR;
&typedef LPSTR PYSTR;
&typedef LPCSTR PCYSTR;
原来只是一系列的类型重定义。ChTraitsBase模板提供了对于char的普通版本和对于wchar_t的特化版本。如果CSimpleStringT模板传入的是char型,则使用ChTraitsBase&char&实现;如果CSimpleStringT传入的是wchar_t型则使用ChTraitsBase&wchar_t&来实现。另外注意到char和wchar_t的XCHAR和YCHAR的定义被交换过来了。
单独的CSimpleStringT模板也是可以使用的,只不过它的功能比较简单,所以取名为Simple。它有如下定义:
typedefCSimpleStringT& TCHAR & CSimpleS
typedef CSimpleStringT& char & CSimpleStringA;
typedef CSimpleStringT& wchar_t & CSimpleStringW;
继续来看CSimpleStringT的实现代码。
CSimpleStringT(_In_ IAtlStringMgr* pStringMgr )
CSimpleStringT( _In_ const CSimpleStringT& strSrc )
CSimpleStringT( _In_ const CSimpleStringT&BaseType, !t_bMFCDLL&&strSrc )
CSimpleStringT( _In_ PCXSTR pszSrc, _In_ IAtlStringMgr* pStringMgr )
CSimpleStringT( _In_ const XCHAR* pchSrc, _In_ int nLength, _In_ IAtlStringMgr*pStringMgr )
它提供了5个构造函数,其中第2、3个属于拷贝构造函数,可以略去不管。而其他的3的构造函数中都需要一个参数,即IAtlStringMgr*
pStringMgr。这个参数是做什么用的呢?那就继续追踪IAtlStringMgr吧。
IAtlStringMgr在atlsimpstr.h文件中实现。
__interface IAtlStringMgr
&&&&&&&&// Allocate a newCStringData
&&&&&&&&CStringData* Allocate(int nAllocLength, int nCharSize ) throw();
&&&&&&&&// Free an existingCStringData
&&&&&&&&void Free(CStringData* pData ) throw();
&&&&&&&&// Change the size ofan existing CStringData
&&&&&&&&CStringData*Reallocate( CStringData* pData, int nAllocLength, int nCharSize ) throw();
&&&&&&&&// Get the CStringDatafor a Nil string
&&&&&&&&CStringData*GetNilString() throw();
&&&&&&&&IAtlStringMgr* Clone()throw();
IAtlStringMgr原来是用于分配和释放String的内存的。而且可以看到IAtlStringMgr分配后的内存被格式化为CStringData格式。这个CStringData先放着不管,继续回到CSimpleStringT,看看这些构造函数的具体实现。
CSimpleStringT( _In_ IAtlStringMgr* pStringMgr )
&&&&&&&&ATLENSURE( pStringMgr!= NULL );
&&&&&&&&CStringData* pData =pStringMgr-&GetNilString();
&&&&&&&&Attach( pData );
如果CSimpleStringT模板对象在构造的时候不传入字符串数据,就会由内存管理模块分配一个空串给该CSimpleStringT模板对象。
CSimpleStringT( _In_ PCXSTR pszSrc, _In_ IAtlStringMgr* pStringMgr )
&&&&&&&&ATLENSURE( pStringMgr!= NULL );
&&&&&&&&int nLength =StringLength( pszSrc );
&&&&&&&&CStringData* pData =pStringMgr-&Allocate( nLength, sizeof( XCHAR ) );
&&&&&&&&if( pData == NULL )
&&&&&&&&&&&&&&&&&&ThrowMemoryException();
&&&&&&&&Attach( pData );
&&&&&&&&SetLength( nLength );
&&&&&&&&CopyChars( m_pszData,nLength, pszSrc, nLength );
如果CSimpleStringT模板对象在构造的时候传入字符串(可定长和不定长),就会由内存管理模块分配一个指定长度的缓冲区给该CSimpleStringT模板对象,然后再将具体数据拷贝到指定的缓冲区。
应该看看Attach()的实现。到底是怎么绑定缓冲区的呢?
void Attach( _In_ CStringData* pData ) throw()
&&&&&&&&m_pszData =static_cast& PXSTR &( pData-&data() );
它将一个CStringData对象的数据指针传递给模板对象的成员变量m_pszData,这样CSimpleStringT就可以通过m_pszData直接操作数据缓冲区了。
现在可以总结一下了:
CSimpleStringT模板对象需要传递一个IAtlStringMgr类型的内存管理器,通过IAtlStringMgr管理器分配指定长度的格式化为CStringData类型数据的缓冲区,然后将CStringData的数据部分的指针传递给CSimpleStringT的成员m_pszData,这样CSimpleStringT就可以通过m_pszData指针方便的操作属于它的数据缓冲区了。
但是还有一个问题没有解决,到底m_pszData指向何方。这个问题先不做回答。CSimpleStringT模板的实现就算结束了,回过头再来看看CStringT模板是怎么实现的。
首先看到的也是一些类型的重定义:
typedef CSimpleStringT& BaseType,_CSTRING_IMPL_::_MFCDLLTraitsCheck&BaseType,StringTraits&::c_bIsMFCDLLTraits & CThisSimpleS
typedef StringTraits StrT
typedef typename CThisSimpleString::XCHAR XCHAR;
typedef typename CThisSimpleString::PXSTR PXSTR;
typedef typename CThisSimpleString::PCXSTR PCXSTR;
typedef typename CThisSimpleString::YCHAR YCHAR;
typedef typename CThisSimpleString::PYSTR PYSTR;
typedef typename CThisSimpleString::PCYSTR PCYSTR;
这里不过是想把在CSimpleStringT模板定义的数据类型继承下来而已。这只是一种技巧。
下面来看一看CStringT的构造函数,由于它的构造函数比较多,所以只挑选出几个能说明问题的构造函数。
CStringT() throw() : CThisSimpleString(StringTraits::GetDefaultManager() )
CStringT( IAtlStringMgr* pStringMgr ) throw() : CThisSimpleString(pStringMgr )
CStringT( const CStringT& strSrc ) :&&&&&&&&CThisSimpleString( strSrc )
CStringT( _In_opt_z_ const XCHAR* pszSrc ) : CThisSimpleString(StringTraits::GetDefaultManager() )
CStringT( _In_opt_z_ const YCHAR* pszSrc ) : CThisSimpleString(StringTraits::GetDefaultManager() )
CStringT( _In_opt_z_ LPCSTR pszSrc, _In_ IAtlStringMgr* pStringMgr ): CThisSimpleString( pStringMgr )
CStringT( _In_opt_z_ LPCWSTR pszSrc, _In_ IAtlStringMgr* pStringMgr) : CThisSimpleString( pStringMgr )
CStringT( _In_ char ch, _In_ int nLength = 1 ) : CThisSimpleString(StringTraits::GetDefaultManager() )
CStringT( _In_ wchar_t ch, _In_ int nLength = 1 ) : CThisSimpleString(StringTraits::GetDefaultManager() )
CStringT(const XCHAR* pch, _In_ int nLength ) : CThisSimpleString(pch, nLength, StringTraits::GetDefaultManager() )
CStringT(const XCHAR* pch, _In_ int nLength, _In_ IAtlStringMgr*pStringMgr ) : CThisSimpleString( pch, nLength, pStringMgr )
CStringT(const YCHAR* pch, _In_ int nLength ) : CThisSimpleString(StringTraits::GetDefaultManager() )
CStringT(const YCHAR* pch, _In_ int nLength, _In_ IAtlStringMgr*pStringMgr ) :&&&&&&CThisSimpleString(pStringMgr )
主要分为以下几类:
l空构造函数,即不带任何参数的构造函数。
l拷贝构造函数。
l由指定和不指定长度的字符串构造,兼容CHAR和WCHAR版本,方便MultiByte和Unicode编码之间转换。
l由单独的CHAR或者WCHAR构造。
这些分类中又分为指定IAtlStringMgr对象的版本和不指定IAtlStringMgr对象的版本。
下面我们将注意力集中到StringTraits::GetDefaultManager()这段话上,看样子它应该是一个静态函数而且返回IAtlStringMgr类型对象。
来看一看StringTraits的定义吧——哦,这只是一个模板参数。还记得CStringT是怎么定义的吗?
#ifndef _ATL_CSTRING_NO_CRT
typedef CStringT& wchar_t, StrTraitATL& wchar_t,ChTraitsCRT& wchar_t & & & CAtlStringW;
typedef CStringT& char, StrTraitATL& char, ChTraitsCRT&char & & & CAtlStringA;
typedef CStringT& TCHAR, StrTraitATL& TCHAR, ChTraitsCRT&TCHAR & & & CAtlS
#else&// _ATL_CSTRING_NO_CRT
typedef CStringT& wchar_t, StrTraitATL& wchar_t & &CAtlStringW;
typedef CStringT& char, StrTraitATL& char & &CAtlStringA;
typedef CStringT& TCHAR, StrTraitATL& TCHAR & &CAtlS
#endif&// _ATL_CSTRING_NO_CRT
看来StringTraits应该是StrTraitATL& wchar_t, ChTraitsCRT& wchar_t & &或者StrTraitATL&wchar_t &了。
我们继续来揭开StrTraitATL的面纱吧。
template& typename _BaseType = char, class StringIterator =ChTraitsOS& _BaseType & &
class StrTraitATL : public StringIterator
&&&&&&&&static IAtlStringMgr*GetDefaultManager() throw()
&&&&&&&&&&&&&&&&&&return(&g_strmgr );
经过一番纠结(开始的时候语法没有看懂),终于明白了StrTraitATL实际继承自ChTraitsOS& _BaseType &,而且ChTraitsOS&_BaseType
&是一个模板参数。先不急着弄明白ChTraitsOS是什么。看到了一个静态函数GetDefaultManager(),而且返回IAtlStringMgr类型对象,这应该就是我们要找的了。它的实现很简单,返回的是一个全局的可以转换为IAtlStringMgr类型的对象g_strmgr:
externCAtlStringMgr g_
怎么是一个extern的对象呢!这下子让我去哪里找g_strmgr的实现呢?我注意到了一个新的类型CAtlStringMgr,这又是何许人也?CAtlStringMgr被定义于atlstr.h文件。
classCAtlStringMgr : public IAtlStringMgr
首先看到它的定义就明白了,原来CAtlStringMgr继承自IAtlStringMgr接口。
CAtlStringMgr(_In_opt_ IAtlMemMgr* pMemMgr = NULL ) throw() : m_pMemMgr( pMemMgr )
这是它唯一的构造函数。而且注意到CAtlStringMgr的成员变量m_pMemMgr是一个IAtlMemMgr类型的对象。看来CAtlStringMgr只是对IAtlMemMgr类型的一种包装。看看其他成员的具体实现,证明了猜想是正确的。IAtlMemMgr被定义于atlmem.h文件。
__interface__declspec(uuid(&654F7EF5-CFDF-4df9-A450-6C6A13C622C0&)) IAtlMemMgr
&&&&&&&&void* Allocate( size_tnBytes ) throw();
&&&&&&&&void Free( void* p )throw();
&&&&&&&&void* Reallocate(void* p, size_t nBytes ) throw();
&&&&&&&&size_t GetSize( void*p ) throw();
可是这只是一个接口,有没有具体实现的类呢?有!就在这个接口定义的下面。从IAtlMemMgr接口继承的类实现了4个:
class CCRTHeap : public IAtlMemMgr,是对malloc/realloc/free的封装。
class CWin32Heap : public IAtlMemMgr,是对HeapAlloc/HeapReAlloc/HeapFree的封装。
class CLocalHeap : public IAtlMemMgr,是对LocalAlloc/LocalReAlloc/LocalFree的封装。
class CGlobalHeap : public IAtlMemMgr,是对GlobalAlloc/GlobalReAlloc/GlobalFree的封装。
如果你需要一个简单内存分配,则只需实现一个CCRTHeap对象;如果你需要一个全局堆上的内存分配,则只需要实现一个CGlobalHeap对象。这样就给CSimpleStringT模板的数据分配带来了极大的灵活性。
弄明白了最终的内存分配是怎么实现的,我们再回头来看ChTraitsOS是做什么用的?它肯定不只是内存分配这么简单。ChTraitsOS的定义是这样的:
template& typename _CharType = char &
class ChTraitsOS : public ChTraitsBase& _CharType &
第一感觉是,这个类肯定还有一个wchar_t的特化版本,果然在这个类的后面紧接着就是它的特化版本的实现。继续往下看:
static int tclen(_In_z_ LPCSTR p) throw()
static LPCSTR strchr(_In_z_ LPCSTR p, _In_ char ch) throw()
static LPCSTR strchr_db(_In_z_ LPCSTR p, _In_ char ch1, _In_ charch2) throw()
static int GetCharLen(_In_z_ const char* psz) throw()
都是一些静态函数呢,函数的定义也基本上都是和字符(串)的处理有关。这样看来,ChTraitsOS类的实际功能是提供了一些对字符(串)的辅助操作。(而如果你清楚ChTraitsOS的字面含义的话就更加确定你的结论了。ChTraitsOS应该是char‘s
traits of os的缩写,翻译为中文就是”操作系统字符的性状”。)
不知道你有没有注意到ChTraitsOS只是StrTraitATL的一个默认的模板参数,当我们回头看CString定义的时候,你会发现StrTraitATL还接受了另外一种模板参数ChTraitsCRT,必然的ChTraitsCRT是ChTraitsOS的一个子类,并且在同样功能的基础上提供了对CRT(C
runtime library)的支持。
至此为止,CStringT模板的剖析就可以结束了。至于CSimpleStringT的第二个模板参数t_bMFCDLL到底是什么意思,在最后我会讲一个小故事来说明。
最终的CStringT模板结构如下图所示:
记得我们还没有说CStringData的结构呢。CStringData被定义在atlsimpstr.h文件内:
struct CStringData
&&&&IAtlStringMgr*pStringM&// String manager for thisCStringData
&&&&int nDataL&// Length of currently used data in XCHARs(not including terminating null)
&&&&int nAllocL&// Length of allocated data in XCHARs (notincluding terminating null)
&&&&long nR&&&&// Reference count: negative == locked
&&&&// XCHARdata[nAllocLength+1]&// A CStringData isalways followed in memory by the actual array of character data
&&&&void* data() throw()
&&&&&&&&&&&&&return (this+1);
&&&&void AddRef() throw()
&&&&&&&&&&&&&ATLASSERT(nRefs& 0);
&&&&&&&&&&&&&_AtlInterlockedIncrement(&nRefs);
&&&&bool IsLocked() constthrow()
&&&&&&&&&&&&&return nRefs &0;
&&&&bool IsShared() constthrow()
&&&&&&&&&&&&&return( nRefs &1 );
&&&&void Lock() throw()
&&&&&&&&&&&&&ATLASSERT( nRefs&= 1 );
&&&&&&&&&&&&&nRefs--;&// Locked buffers can't be shared, so nointerlocked operation necessary
&&&&&&&&&&&&&if( nRefs == 0 )
&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&nRefs =-1;
&&&&&&&&&&&&&}
&&&&void Release() throw()
&&&&&&&&&&&&&ATLASSERT( nRefs!= 0 );
&&&&&&&&&&&&&if( _AtlInterlockedDecrement(&nRefs ) &= 0 )
&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&pStringMgr-&Free(this );
&&&&&&&&&&&&&}
&&&&void Unlock() throw()
&&&&&&&&&&&&&ATLASSERT(IsLocked() );
&&&&&&&&&&&&&if(IsLocked())
&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&nRefs++;&// Locked buffers can't be shared, so nointerlocked operation necessary
&&&&&&&&&&&&&&&&&&&&&&if(nRefs == 0 )
&&&&&&&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&nRefs= 1;
&&&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&}
可以看到CStringData对象可以被多次引用,以减少空间的占用。并提供锁定功能已保证在多线程环境中的读写安全。它的内部还包含了一个IAtlStringMgr内存分配器的指针,用于将自身在没有引用的时候通知内存分配器内销毁。
在这里有一个比较奇怪的函数data(),为什么这么说呢?看一下他的实现吧。return (this+1);根据数据类型加减法则,data()函数返回的地方应该是这个CStringData对象结束的下一个内存地址。难道说CStringData对象和数据区域是连续分配的?是的,的确如此!
我们看一下CAtlStringMgr的Allocate()函数:
nChars =AtlAlignUp( nChars + 1, 8 );&// Preventexcessive reallocation.&The heap willusually round up anyway.
&&&&&&&& if(&&&&&FAILED(::ATL::AtlMultiply(&nDataBytes,static_cast&size_t&(nChars), static_cast&size_t&(nCharSize))) ||
&&&&&&&&&&&&&&&&&& FAILED(::ATL::(&nTotalSize,static_cast&size_t&(sizeof( CStringData )), nDataBytes)))
&&&&&&&& {
&&&&&&&&&&&&&&&&&& returnNULL;
&&&&&&&& }
&&&&&&&& pData= static_cast& CStringData* &( m_pMemMgr-&Allocate( nTotalSize ) );
&&&&&&&& 第一句话的意思是,将待分配的内存长度始终计算为8的倍数。第二句分为两段,AtlMultiply()函数是一个乘法,翻译直白点就是nCharBytes = char*sizeof(char),AtlAdd()函数是一个加法,翻译直白点是sizeof(CStringData)
+ nCharBytes = nTotalSize。也就是说每一次内存分配都在原有的承载字符串的空间大小上增加一个CStringData对象的空间。而且分配的内存是被格式化为CStringData对象的,也就是说CStringData对象的数据在分配的内存的前端,然后紧跟着的是分配给客户使用的实际内存,即this+1。
以上就是我分析得出的关于CString结构的所有东西了。
--------------------------------------------------------
文章最后是我从网络上找到的一篇关于CString如何产生的故事。原文链接如下:&
话说,某一天ATL开发小组发现老是操作char,太低效,STL的string也不是很好用,于是乎,他们做了一个为ATL服务的简单的字符串类,名字叫
CSimpleStringT,通过typedef,定义成了 CSimpleString。
后天某一天,MFC的人也发现char和string超不好用,他们发现公司的ATL小组已经做了一个成熟CSimpleString类,于是MFC小组拿来直接使用。在使用中,MFC小组的人发现CSimpleString做的太简单了,有很多的功能,它都不提供,另外,类函数设计的也不好用。于是MFC小组的成员决定扩展CSimpleString,他们将扩展的代码写进cstringt.h中,另外抽离出对外的接口头文件afxstr.h,将定义放在了这。(到这里,我们发现了上面提到问题的发生点,MFC的头文件继承了ATL头文件)。
又到后来,MFC小组的某个成员(主程级)转到了ATL小组,来到ATL小组后,他发现,平日用惯了CString,现在要用CSimpleString真TM憋屈,于是他建议在ATL中自封装一个CStrnig。ATL小组发现,继然MFC的CString已经做得这么成熟稳定且好用了,自己没必要再另起炉灶,另外,他们发现cstringt.h是独立于MFC其它文件的,虽然属于MFC小组(MFC小组所写),但是引用的却都是atl的头文件,因此,引用cstringt.h不会融入MFC其它旁大的文件,因此可行。所以综合以上考虑,ATL小组直接继承于cstringt头文件,派生了自己的CString,放在了atlstr.h中。(注意,连名字取得都和afxstr.h相对应,到这里,我们又看到,ATL头文件继承了MFC头文件)。
就这样,诞生了两份CSring。日子很平淡的一天一天过去,直到有一天,有个项目要混用ATL和MFC,他们发现,有两份CString,编译不过!因为ATL的CString毕竟只是模仿MFC,于是ATL让路,加上了宏定义
#ifndef _AFX ,意即,在没有使用MFC时,ATL才定义CString。
ATL 和 MFC CString的故事讲完了,相信大家对CString相关文件目前结构的来龙去脉应该很清楚了。但是WTL呢?为什么WTL也要定义一个CString?话说WTL编写过程中,WTL组的后生小辈们看了ATL的CString代码,他们觉得咋这CString搞得咋这么复杂呢?看得头都大了,于是他们设计了一个四两拨千斤的CString,不继承任何东西,不依赖任何东西,就是一个简简单单的类。在初期,他们工作得很好,但是到后期,他们发现,如果两个人的代码用的是不同的CString的话,那么将代码合并的时候,编译不过,和之前遇到的问题一样,会产生两个CString,于是WTL不得不加了另外一个宏
_WTL_NO_CSTRING 来禁止WTL CString的编译。
好了,故事全都讲完了,ATL、WTL、MFC,结论是,先有CAtlSimpleString,后有MFCCString,再有ATL
CString,最后有WTL CString,唉,微软的人搞这么复杂干嘛呢…
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:17697次
排名:千里之外
原创:10篇
(1)(2)(2)(2)(3)1588人阅读
主&&&&&&题: 混用ATL MFC WTL的问题-CString的冲突
作&&&&&&者: mc_
回复次数: 3
MFC的定义是全局的,和ATL混用好像没啥问题,不过和WTL混在一起要出现CString的冲突,说是无法解析多个定义。
atlstr.h是这样定义的,也就是在混合MFC的情况下ATL里头的CString 的定义被取消掉了
#ifndef _AFX
typedef CAtlStringW CStringW;
typedef CAtlStringA CStringA;
typedef CAtlString CS
afxstr.h是这样定义的
typedef ATL::CStringT& wchar_t, StrTraitMFC& wchar_t & & CStringW;
typedef ATL::CStringT& char, StrTraitMFC& char & & CStringA;
typedef ATL::CStringT& TCHAR, StrTraitMFC& TCHAR & & CS
这两种CString肯定是一回事,不过为了顺利使用WTL,还是需要ATL名称空间里的ATL::CString,虽然可以使用ATL::CAtlString,WTL里面肯定不会认CAtlString
我在stdafx.h里头试图用#undef CString 去掉全局的MFC CString,没有成功, 用#undef _AFX 使用在ATL头文件之前定义一下,也没成功
问哈大家有啥子好办法?MFC可否被定义成名称空间namespace,不过试了下错误一大堆
回复人: carr123
#define _WTL_NO_CString
回复人: mc_
感谢,这个问题我已解决,_WTL_NO_CSTRING 只能消除WTL里定义的CString
回复人: mc_
关于这个问题的解决办法,本人现在贴出来分享
关键在这两个声明上
#undef __ATLSTR_H__&&&&
#define _ATL_TMP_NO_CSTRING&&&&//本人用的是WTL81_9127
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:168756次
积分:2472
积分:2472
排名:第10553名
原创:49篇
转载:111篇
评论:20条
(1)(1)(1)(2)(4)(2)(1)(1)(3)(9)(5)(2)(9)(5)(13)(8)(12)(22)(14)(7)(11)(8)(14)(1)(3)(3)请问:如何让CString::Find(),查找字符或字符窜时不区分大小写?
[问题点数:20分,结帖人kucao]
请问:如何让CString::Find(),查找字符或字符窜时不区分大小写?
[问题点数:20分,结帖人kucao]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。CString学习_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
CString学习
上传于||文档简介
&&C​S​t​r​i​n​g​学​习
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
下载文档到电脑,查找使用更方便
还剩24页未读,继续阅读
你可能喜欢2047人阅读
转自:http://dryfish118./Blog/cns!FDCABF8EDB.entry
&&&&VC6的时候记得看过CString的源代码,并不复杂,应该是从VC7开始,MFC和ATL共用一个CString了,新的CString使用了模板技术和其它技术,值得一提。&&&&&&&&先&看CString的定义:typedef CAtlString CS如果想明确使用ANSI和UNICODE版本,可以使用CStringA和CStringW,看它们的定义:typedef CAtlStringW CStringW;typedef CAtlStringA CStringA;以上三个Atl版本的String,其定义为:typedef CStringT& wchar_t, StrTraitATL& wchar_t & & CAtlStringW;typedef CStringT& char, StrTraitATL& char & & CAtlStringA;typedef CStringT& TCHAR, StrTraitATL& TCHAR & & CAtlS因此,CStringT才是真实的CString类。template& typename BaseType, class StringTraits &class CStringT : &&& public CSimpleStringT& BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck&BaseType, StringTraits&::c_bIsMFCDLLTraits &{};CStringT有两个模板参数,第一个表明字符类型,第二个参数从源代码中知道是StrTraitATL:template& typename _BaseType = char, class StringIterator = ChTraitsOS& _BaseType & &class StrTraitATL : public StringIterator{public:&&& static HINSTANCE FindStringResourceInstance(__in UINT nID) throw()&&& {&&&&&&& return( AtlFindStringResourceInstance( nID ) );&&& }
&&& static IAtlStringMgr* GetDefaultManager() throw()&&& {&&&&&&& return( &g_strmgr );&&& }};从类声明看到他提供了一个字符串管理器,字符迭代器和从资源中获得字符串的功能。字符串管理器比较重要,后面会提到。CStringT没有成员变量,封装了很多好用的字符串函数,数据在基类CSimpleStringT中。CSimpleStringT只有一个成员变量m_pszData,不要小看这个变量,在它身上,有着很多秘密,绝对不是他的声明那么朴实:PXSTR m_pszDPXSTR就是char或者wchar_t,只不过被模板的特化技术封装了一下。CSimpleStringT没有直接操作m_pszData,而是通过成员函数GetData来获得,看一下这个函数:CStringData* GetData() const throw(){&&& return( reinterpret_cast& CStringData* &( m_pszData )-1 );}这个函数将m_pszData指向的内存转成CStringData类型,然后往前移动sizeof(CStringData)的长度,指向了一个CStringData对象。m_pszData的秘密就在此处,实际上,每次分配内存时,都会多分配一段sizeof(CStringData)长度的内存,最前面这段数据格式化为CStringData对象,然后m_pszData指向其后的数据,这才是字符串。|_______________|___________________________________________________|CStringData&&&& m_pszData再看CStringData的声明:struct CStringData{&&& IAtlStringMgr* pStringM& // String manager for this CStringData&&& int nDataL& // Length of currently used data in XCHARs (not including terminating null)&&& int nAllocL& // Length of allocated data in XCHARs (not including terminating null)&&& long nR&&&& // Reference count: negative == locked&&& // XCHAR data[nAllocLength+1]& // A CStringData is always followed in memory by the actual array of character data};CStringData包含了这个字符串的所有信息,包括字符串长度,内存长度和引用计数,另外还有一个字符串管理器指针,这个指针从前面所提到的模板参数StrTraitATL中得到。再看看接口IAtlStringMgr的声明:__interface IAtlStringMgr{public:&&& // Allocate a new CStringData&&& CStringData* Allocate( int nAllocLength, int nCharSize ) throw();&&& // Free an existing CStringData&&& void Free( CStringData* pData ) throw();&&& // Change the size of an existing CStringData&&& CStringData* Reallocate( CStringData* pData, int nAllocLength, int nCharSize ) throw();&&& // Get the CStringData for a Nil string&&& CStringData* GetNilString() throw();&&& IAtlStringMgr* Clone() throw();};IAtlStringMgr提供了字符串内存的分配和销毁。具体实现参考类CAfxStringMgr。
我们还是先看看一个字符串是如何赋值的吧,给下面第二行代码加上断点,调试进入:CSs = L"Hello world";一直跟踪到wmemcpy_s函数,才找到了拷贝的函数,以下是堆栈:s = L"Hello world";CStringT::operator=()&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // a& CSimpleStringT::operator=()&&&&&&&&&&&&&&&&&&&&&& // b&& SetString(const wchar_t * pszSrc)&&&&&&&&&&&&&&& // c&&& SetString(const wchar_t * pszSrc, int nLength)& // d&&&& CopyChars&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // e一行行来分析:a,调用基类CSimpleStringT的操作符=b,调用SetStringc,求字符串pszSrc长度,调用两个参数的SetStringd,调用GetBuffer分配内存空间,然后判断新字符串是否与现有字符串重叠,重叠调用CopyCharsOverlapped拷贝新字符串,不重叠调用CopyCharse,CopyChars就是wmemcpy_s在上面的步骤中,值得关注的GetBuffer函数。我们继续进入这个函数看看发生了什么:SetStringGetBuffer&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // a& PrepareWrite&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // b&& PrepareWrite2&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // c&&& Fork&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // d&&&& CAfxStringMgr::Allocate&&&&&&&&&&&&&&&&&&&&&&& // e&&&&& _malloc_dbg&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // fa,调用PrepareWriteb,判断引用计数是否大于1或者长度不够,满足任意一个条件,都需要调用PrepareWrite重新分配内存,否则直接返回m_pszDatac,首先判断新申请的长度是否小于已经内存长度,如果小于,则将长度设置为已有内存长度。然后判断引用计数是否大于1,是则调用Fork重新申请内存。如果引用计数不大于1,则看是否需要申请内存,是则重新分配。重新分配有一个简单的原则,以下这段比较清楚:if( pOldData-&nAllocLength & nLength ){&&& // Grow exponentially, until we hit 1K.&&& int nNewLength = pOldData-&nAllocL&&& if( nNewLength & 1024 )&&& {&&&&&&& nNewLength += 1024;&&& }&&& else&&& {&&&&&&& nNewLength *= 2;&&& }&&& if( nNewLength & nLength )&&& {&&&&&&& nNewLength = nL&&& }&&& Reallocate( nNewLength );}d,取出旧的CStringData,克隆一个IAtlStringMgr,并分配nLength长度的内存。格式化新分配的内存,并释放旧内存。注意释放的方式,并不是直接free内存,而是调用了CStringData的Release:void Release() throw(){&&& ATLASSERT( nRefs != 0 );
&&& if( _AtlInterlockedDecrement( &nRefs ) &= 0 )&&& {&&&&&&& pStringMgr-&Free( this );&&& }}可以看到只有引用计数小于或等于0了,才会直接free内存。e,具体看代码吧:CStringData* CAfxStringMgr::Allocate( int nChars, int nCharSize ) throw(){&&& size_t nTotalS&&& CStringData* pD&&& size_t nDataB
&&& nDataBytes = (nChars+1)*nCharS&&& nTotalSize = sizeof( CStringData )+nDataB&&& pData = (CStringData*)malloc( nTotalSize );&&& if (pData == NULL)&&&&&&& return NULL;&&& pData-&pStringMgr =&&& pData-&nRefs = 1;&&& pData-&nAllocLength = nC&&& pData-&nDataLength = 0;
&&& return pD}可以看到实际分配的内存大小是字符串长度+1个NULL+sizeof(CStringData)f,分配内存
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2073755次
积分:24699
积分:24699
排名:第173名
原创:518篇
转载:332篇
评论:389条
(2)(1)(6)(2)(1)(2)(3)(1)(3)(4)(4)(2)(2)(1)(2)(1)(23)(4)(1)(3)(5)(9)(7)(13)(5)(6)(15)(6)(17)(8)(24)(23)(8)(13)(11)(36)(44)(9)(8)(6)(24)(28)(46)(13)(65)(21)(14)(21)(12)(5)(1)(2)(1)(2)(3)(4)(5)(7)(6)(2)(6)(6)(2)(4)(10)(15)(13)(23)(11)(11)(30)(32)(31)(7)(6)(4)(16)}

我要回帖

更多关于 atl与catl区别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信