What does CString::GetBuffer() with no size parameter do?

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 );
}

tl;dr

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
An PXSTR 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.
  • Every call to 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.
  • As long as you follow that protocol, the controlled character sequence will always be null-terminated.

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:

  • It is semantically correct. If all you want is a view into the character string, you do not need a pointer to a mutable buffer.
  • There are no superfluous copies of the contents. 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.
  • The immutable interface cannot fail. No exceptions are thrown when calling operator PXCSTR() or GetString().

1 The 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.

2 It 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.

Tags:

C++

Mfc