没有大小参数的CString::GetBuffer()做什么
What does CString::GetBuffer() with no size parameter do?
也许我快疯了,但我已经尝试了我能想到的每一个搜索组合,但我找不到没有参数的CString::GetBuffer()
的定义。我查找的每个引用都描述了CString::GetBuffer( int )
,其中传入的int
参数是最大缓冲区长度。标头中的定义适用于CSimpleStringT::GetBuffer()
。这给了我以下链接,它至少承认了无参数版本的存在,但没有提供对其行为的描述。https://msdn.microsoft.com/en-us/library/sddk80xf.aspx#csimplestringt__getbuffer
我正在研究现有的C++(Visual Studio)代码,如果不需要的话,我不想更改这些代码,但我需要知道CString::GetBuffer()
的预期行为。如果有人能解释一下或给我指一些文件,我将不胜感激。
尽管msdn文档并没有真正说明没有参数的GetBuffer
的作用,但MFC源代码揭示了答案:
return( m_pszData );
所以它只返回一个指向底层字符缓冲区的指针。(它还检查内部数据是否共享,并首先分叉/复制它)。
代码在atlsimpstr.h 中
完整功能:
PXSTR GetBuffer()
{
CStringData* pData = GetData();
if( pData->IsShared() )
{
Fork( pData->nDataLength );
}
return( m_pszData );
}
tl;dr
致电CString::GetString()
。
这是出于错误的原因提出错误的问题。为了解决这个问题,下面是文档中的答案:
返回值
指向对象(以null结尾)字符缓冲区的PXSTR
指针。
对于带有和不带有显式长度参数的重载都是如此。当调用带长度参数的重载时,在返回指向内部缓冲区的指针之前,内部缓冲区可能会调整大小以适应增加的存储需求。
从这一评论中,很明显,这个问题完全是在问错误的事情。要了解原因,您需要了解GetBuffer()
类成员家族的目的是什么:为修改暂时禁用CString
的类不变量1的强制执行,直到通过调用ReleaseBuffer()成员之一再次建立它们。这方面的主要用例是与C代码接口(如Windows API)。
重要信息是:
如果计划直接修改存储的字符序列的内容,则只应调用GetBuffer()
- 在使用任何其他
CString
类成员2之前,对GetBuffer()
的每个调用都必须与对ReleaseBuffer()
的调用相匹配。请特别注意,operator PCXSTR()
和析构函数是类成员 - 只要您遵循该协议,受控字符序列将始终以null结尾
考虑到您的实际用例(Log.Print("%sn", myCstring.GetBuffer())
),前面的内容都不适用。由于您不打算实际修改字符串内容,因此应该访问不可变的CString
接口(例如GetString()或运算符PCXSTR())。这需要常量正确的函数签名(TCHAR const*
与TCHAR*
)。如果不能做到这一点,请使用const_cast
(如果可以确保被调用者不会改变缓冲区)。
这有几个好处:
- 它在语义上是正确的。如果您只需要一个字符串视图,则不需要指向可变缓冲区的指针
- 内容没有多余的副本。
CString
实现了写时复制语义。请求可变缓冲区需要复制共享实例的内容,即使您要在计算当前表达式后立即丢弃该副本 - 不可变接口不能失败。调用
operator PXCSTR()
或GetString()
时不会引发异常
1相关不变量为:1
受控字符序列总是以null结尾。2
GetLength()
返回受控序列中的字符数,不包括空终止符
2如果内容发生更改,则仅严格要求调用其中一个ReleaseBuffer()
实现。从源代码来看,这一点通常并不明显,因此总是调用ReleaseBuffer()
是安全的选择
文档没有结论。查看此处可用的ATL源(https://github.com/dblock/msiext/blob/d8898d0c84965622868b1763958b68e19fd49ba8/externals/WinDDK/7600.16385.1/inc/atl71/atlsimpstr.h-我不声称知道它们是否是官方的)看起来没有参数的GetBuffer()
返回当前缓冲区,如果共享,则在之前克隆它。
另一方面,具有大小的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 );
}
Windows API函数通常需要输入一定长度的字符缓冲区。然后使用GetBuffer(int)
版本。以下代码片段说明了这一点以及GetBuffer()
和GetString()
之间的区别,以及在调用GetBuffer()
:之后调用ReleaseBuffer()
的重要性
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
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 警告处理为错误这里有什么问题
- 什么时候调用组成单元对象的析构函数
- #定义c-预处理器常量..我做错了什么
- 努力将整数转换为链表。不知道我在这里做错了什么
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 什么时候在C++中返回常量引用是个好主意
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- C++避免重复声明的语法是什么
- c++库的公共头文件中应该包含什么
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- ifstream什么都没读
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 我应该使用什么来代替void作为变体中的替代类型之一
- 没有大小参数的CString::GetBuffer()做什么