Perhaps I'm going insane, but I have tried every search combination I can think of, and I can't find a definition for CString::GetBuffer()
with no parameters. Every reference I look up describes CString::GetBuffer( int )
, where the int
parameter passed in is the max buffer length. The definition in the header is for CSimpleStringT::GetBuffer()
. That gave me the following link, which at least acknowledges the existence of the parameterless version, but offers no description of its behavior.
https://msdn.microsoft.com/en-us/library/sddk80xf.aspx#csimplestringt__getbuffer
I'm looking at existing C++ (Visual Studio) code that I don't want to change if I don't have to, but I need to know the expected behavior of CString::GetBuffer()
. I'd appreciate it if someone could explain it or point me to some documentation on it.
Although the msdn documentation doesn't really say what GetBuffer
without a parameter does, the MFC source code reveals the answer:
return( m_pszData );
So it just returns a pointer to the underlying character buffer. (It also checks to see if the internal data is shared and forks/copies it first).
The code is in atlsimpstr.h
Complete function:
PXSTR GetBuffer()
{
CStringData* pData = GetData();
if( pData->IsShared() )
{
Fork( pData->nDataLength );
}
return( m_pszData );
}
Call CString::GetString()
.
This is asking the wrong question for the wrong reasons. Just to get it out of the way, here is the answer from the documentation:
Return Value
AnPXSTR
pointer to the object's (null-terminated) character buffer.
This is true for both overloads, with and without an explicit length argument. When calling the overload taking a length argument, the internal buffer may get resized to accommodate for increased storage requirements, prior to returning a pointer to that buffer.
From this comment, it becomes apparent, that the question is asking for the wrong thing altogether. To learn why, you need to understand what the purpose of the GetBuffer()
family of class members is: To temporarily disable enforcement of CString
's class invariants1 for modification, until establishing them again by calling one of the ReleaseBuffer() members. The primary use case for this is to interface with C code (like the Windows API).
The important information is:
GetBuffer()
should only be called, if you plan to directly modify the contents of the stored character sequence.GetBuffer()
must be matched with a call to ReleaseBuffer()
, before using any other CString
class member2. Note in particular, that operator PCXSTR()
and the destructor are class members.Given your actual use case (Log.Print("%s\n", myCstring.GetBuffer())
), none of the previous really applies. Since you do not plan to actually modify the string contents, you should access the immutable CString
interface (e.g. GetString() or operator PCXSTR()) instead. This requires const-correct function signatures (TCHAR const*
vs. TCHAR*
). Failing that, use a const_cast
if you can ensure, that the callee will not mutate the buffer.
There are several benefits to this:
CString
implements copy-on-write semantics. Requesting a mutable buffer necessitates copying the contents for shared instances, even if you are going to throw that copy away immediately after evaluating the current expression.operator PXCSTR()
or GetString()
.1The relevant invariants are: 1
The controlled sequence of characters is always null-terminated. 2
GetLength()
returns the count of characters in the controlled sequence, excluding the null terminator.
2It is only strictly required to call one of the ReleaseBuffer()
implementations, if the contents were changed. This is often not immediately obvious from looking at the source code, so always calling ReleaseBuffer()
is the safe option.
Documentation is inconclusive. Looking at ATL sources available here (https://github.com/dblock/msiext/blob/d8898d0c84965622868b1763958b68e19fd49ba8/externals/WinDDK/7600.16385.1/inc/atl71/atlsimpstr.h - I do not claim to know if they are official or not) it looks like GetBuffer()
without arguments returns the current buffer, cloning it before if it is shared.
On the other hand, GetBuffer(int)
with size is going to check (through the call to PrepareWrite
and possibly PrepareWrite2
) if the current buffer size is greater than requested, and if it is not, it will allocate the new buffer - thus matching MSDN description.
On a side note, PrepareWrite
seems to become quite creative in how it checks for two conditions:
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 );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With