100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C++

The CString Class

How MFC's CString class manages dynamic text, formatting, searching, and interop with Win32 string APIs.

Collections and UtilitiesBeginner8 min readJul 10, 2026
Analogies

What Is CString?

CString is MFC's dynamic string class, built on the ATL::CStringT template and instantiated as either a Unicode (wchar_t) or MBCS (char) string depending on the TCHAR-based build configuration. Unlike a raw C string, CString automatically manages its own buffer, growing as needed when you append or assign text, and it frees that memory automatically when the CString object goes out of scope, eliminating the manual malloc/free bookkeeping that plain char* code requires.

🏏

Cricket analogy: CString's automatic buffer growth is like a scorecard that automatically adds extra rows whenever a partnership like Kohli and Rahane keeps piling on runs, instead of the scorer needing to tape on new paper by hand.

Construction, Concatenation, and Formatting

CString can be constructed from string literals, other CString objects, or individual characters, and combined with operator+ for simple concatenation, such as CString msg = strFirst + _T(", ") + strLast. For formatted output similar to sprintf, CString::Format(_T("Score: %d, Rank: %s"), nScore, strRank) writes directly into the CString's own buffer, resizing it automatically to fit the result, which avoids the fixed-size buffer overflow risk that raw sprintf into a char array carries.

🏏

Cricket analogy: Format() building a message is like a broadcaster's graphics engine automatically composing 'Kohli: 82 off 54 balls' by substituting live numbers into a template, rather than manually typing a new caption each ball.

cpp
// Building and formatting a CString
CString strFirst = _T("Jane");
CString strLast  = _T("Doe");
CString strFullName = strFirst + _T(" ") + strLast;

int nScore = 87;
CString strMessage;
strMessage.Format(_T("%s scored %d points"), strFullName.GetString(), nScore);

// AfxMessageBox expects LPCTSTR; CString converts implicitly
AfxMessageBox(strMessage);

// Direct buffer manipulation
LPTSTR pBuf = strMessage.GetBuffer(256);
_tcscat_s(pBuf, 256, _T(" - Well done!"));
strMessage.ReleaseBuffer(); // must be called to re-sync length

Searching and Manipulation

CString provides Find() and ReverseFind() for locating substrings or characters, Mid(), Left(), and Right() for extracting portions of the string, and Trim(), MakeUpper(), MakeLower(), and Replace() for in-place transformation. Find() returns -1 when the search text is not present, and Replace() returns the number of replacements made, which is a convenient way to check whether any substitution actually occurred without a separate Find() call first.

🏏

Cricket analogy: Find() locating a substring is like a video analyst scrubbing through footage to find the exact ball where Bumrah bowled the yorker that got the wicket, returning -1 in spirit if no such delivery exists in the over.

CString and Legacy APIs

CString defines an implicit conversion operator to LPCTSTR, which is why you can pass a CString directly to Win32 functions like ::SetWindowText(hWnd, strTitle) without an explicit cast. For cases where a Win32 API needs to write into the buffer directly, GetBuffer(nMinBufferLength) exposes a writable pointer, but you must call ReleaseBuffer() afterward so CString can recompute the string's length and re-establish its internal invariants; skipping ReleaseBuffer leaves the object's cached length out of sync with the actual buffer contents.

🏏

Cricket analogy: The implicit LPCTSTR conversion is like a translator automatically converting a scorer's handwritten notes into the official ICC scoresheet format whenever officials request it, without the scorer rewriting anything.

Older versions of CString (pre-Visual C++ 2005) used a copy-on-write reference-counted implementation for efficiency, but this was removed because it was not thread-safe: two CString objects sharing the same buffer across threads could corrupt each other's data. Modern CString always performs a deep copy on assignment, trading a little performance for correctness in multithreaded MFC applications.

Calling GetBuffer() to get a writable pointer and then failing to call ReleaseBuffer() before the CString is used again leaves its cached length field out of sync with the actual null-terminated contents, which can produce truncated strings, garbage characters, or crashes in subsequent operations like Format() or Find().

  • CString is a dynamically resizing string class built on ATL::CStringT, instantiated for Unicode or MBCS via TCHAR.
  • Format() writes sprintf-style formatted text directly into CString's self-managed buffer.
  • Find, Mid, Left, Right, Trim, and Replace provide searching and manipulation without manual buffer math.
  • CString implicitly converts to LPCTSTR for seamless use with Win32 APIs.
  • GetBuffer()/ReleaseBuffer() must always be paired to keep the internal length in sync.
  • Modern CString always deep-copies on assignment; the old reference-counted implementation was removed for thread safety.
  • CString eliminates most manual malloc/free bookkeeping compared to raw char* string handling.

Practice what you learned

Was this page helpful?

Topics covered

#MFCMicrosoftFoundationClassesStudyNotes#MicrosoftTechnologies#TheCStringClass#CString#Class#Construction#Concatenation#OOP#StudyNotes#SkillVeris