也许我疯了,但是我尝试了所有我能想到的搜索组合,但找不到没有参数的CString::GetBuffer()
的定义。我查询的每个参考都描述了CString::GetBuffer( int )
,其中传入的int
参数是最大缓冲区长度。标头中的定义适用于CSimpleStringT::GetBuffer()
。这给了我以下链接,该链接至少承认无参数版本的存在,但是没有提供其行为的描述。
https://msdn.microsoft.com/en-us/library/sddk80xf.aspx#csimplestringt__getbuffer
我正在查看不需要的情况下不想更改的现有C ++(Visual Studio)代码,但是我需要知道CString::GetBuffer()
的预期行为。如果有人可以解释它或为我指出一些文档,我将不胜感激。
答案 0 :(得分:6)
尽管msdn文档并未真正说明没有参数的GetBuffer
的含义,但MFC源代码揭示了答案:
return( m_pszData );
因此,它仅返回指向基础字符缓冲区的指针。 (它还会检查内部数据是否共享,并首先派生/复制)。
代码在atlsimpstr.h
中完整功能:
PXSTR GetBuffer()
{
CStringData* pData = GetData();
if( pData->IsShared() )
{
Fork( pData->nDataLength );
}
return( m_pszData );
}
答案 1 :(得分:1)
文档没有定论。查看此处可用的ATL源(https://github.com/dblock/msiext/blob/d8898d0c84965622868b1763958b68e19fd49ba8/externals/WinDDK/7600.16385.1/inc/atl71/atlsimpstr.h –我不知道它们是否是官方的),看起来GetBuffer()
不带参数将返回当前缓冲区,如果共享则将其克隆。< / p>
另一方面,具有大小的GetBuffer(int)
将检查(通过调用PrepareWrite
并可能检查PrepareWrite2
)当前缓冲区的大小是否大于请求的大小,以及是否大于请求的大小不会,它将分配新缓冲区-从而匹配MSDN描述。
另一方面,PrepareWrite
在检查两个条件方面似乎变得很有创意:
PXSTR PrepareWrite( __in int nLength )
{
CStringData* pOldData = GetData();
int nShared = 1-pOldData->nRefs; // nShared < 0 means true, >= 0 means false
int nTooShort = pOldData->nAllocLength-nLength; // nTooShort < 0 means true, >= 0 means false
if( (nShared|nTooShort) < 0 ) // If either sign bit is set (i.e. either is less than zero), we need to copy data
{
PrepareWrite2( nLength );
}
return( m_pszData );
}
答案 2 :(得分:1)
这是出于错误原因而提出的错误问题。只是为了摆脱它,这是documentation的答案:
返回值
PXSTR
指针,指向对象的(以null结尾的)字符缓冲区。
对于有和没有显式长度参数的两个重载都是如此。在调用带有长度参数的重载时,在返回指向该缓冲区的指针之前,可能会调整内部缓冲区的大小以适应不断增长的存储需求。
从this comment可以明显看出,问题完全是在请求错误的东西。要了解原因,您需要了解GetBuffer()
类成员家族的目的是:暂时 禁止执行CString
的类不变量 1 < / sup>修改 ,直到通过调用ReleaseBuffer()成员之一再次建立它们。这样做的主要用例是与C代码(例如Windows API)接口。
重要信息是:
GetBuffer()
仅在您打算直接修改存储的字符序列的内容时才应调用。GetBuffer()
类成员 2 之前,对ReleaseBuffer()
的每次调用都必须与对CString
的调用相匹配。特别注意,operator PCXSTR()
和析构函数是类成员。鉴于您的实际用例(Log.Print("%s\n", myCstring.GetBuffer())
),上述任何一个都不适用。由于您实际上并不打算修改字符串内容,因此应该访问不可变的CString
接口(例如GetString()或operator PCXSTR())。这需要使用const正确的函数签名(TCHAR const*
与TCHAR*
)。失败的话,请使用const_cast
(如果可以确保被调用者不会突变缓冲区)。
这有几个好处:
CString
实现了写时复制语义。请求可变缓冲区需要复制共享实例的内容,即使您要在评估当前表达式后立即丢弃该副本。operator PXCSTR()
或GetString()
时不会引发异常。 1 相关的不变式为:1
受控字符序列始终以空值结尾。 2
GetLength()
返回受控序列中的字符数,不包括空终止符。
2 如果更改了内容,则仅严格要求调用ReleaseBuffer()
实现之一。从源代码看,这通常通常不会立即显现出来,因此总是调用ReleaseBuffer()
是安全的选择。
答案 3 :(得分:1)
Windows API函数通常需要输入一定长度的字符缓冲区。然后使用GetBuffer(int)
版本。以下代码段说明了这一点以及GetBuffer()
和GetString()
之间的区别以及在调用ReleaseBuffer()
之后调用GetBuffer()
的重要性:
CStringW FullName;
if(::GetModuleFileNameW(nullptr,FullName.GetBuffer(MAX_PATH), MAX_PATH) <= 0)
return 0; //GetBuffer() returns PXSTR
FullName.ReleaseBuffer(); //Don't forget!
FullName = L"Path and Name: " + FullName;
std::wcout << FullName.GetString() << L"\n"; //GetString() returns PCXSTR