The Evils of Declaring Global const CString Objects

 

Most of the MFC programmers has tendency to declare the global const CString objects instead of global const char* array (or LPCTSTR) as string constants.

To optimize the storage of constant data, you have to make sure that the constant data is always get stored with your program. Before going to CString specific issues, let’s go take some other examples.

If you want it to be a constant, you must declare it as an initialized const static or global variable as follows. (If no const specified there, it will not be stored with your program)

[sourcecode language='cpp']
const char g_pch[] = “test”;[/sourcecode]

If several instances of your program are running, the same EXE and DLL files will be mapped to each process’s virtual address space. To know what’s happening inside and to

know where the constant data being stored, we’ve to understand about the different sections that Visual C++ Linker generates. Some of the important sections and their characteristics are as follows
Name Type Access Contents
.text Code Read-only Program code
.rdata Data Read-only Constant initialized data
.data Data Read/write Non-constant initialized data
.bss Data Read/write Non-constant uninitialized data

The g_pch data we mentioned before will be stored under .rdata section which is part of the program. it’s happened because the data is constant (declared as const).

The linker will put the built in types and even structures as global constant as part of programs. But the case is different for C++ objects. C++ objects should be initialized using constructors, thus the compiler will generate code for constructors and destructors. Take the following example

[sourcecode language='cpp']
const CRect g_rect(0, 0, 100, 100);
[/sourcecode]

In the above example, the data (g_rect) will be stored under .bss section and initializes, when the program loads. The things are more evil if you use CString objects. Consider the following example.

[sourcecode language='cpp']
const CString g_str(“Hello World!”);
[/sourcecode]

In this case the CString object will be put inside the .bss section and there’s a constant string which we passed to the constructor. It will be stored under .data section (as we have not specified it as const). In addition to that, CString objects are keeping data by dynamically allocating memory in the heap. To optimize the storage of constant data, it’s always better to declare strings are const char* or if your program wants to support both UNICODE and non-UNICODE build, then delcare it as

[sourcecode language='cpp']LPCTSTR g_pch = _T(“Hello World”);[/sourcecode]

So take care of Global CString constants. I got this nice tip from the book “Programming Visual C++” by David J. Kruglinski

 
This entry was posted in Uncategorized. Bookmark the permalink.
  • Michael Gebis

    A minor point, but I believe this is wrong:

    “It will be stored under .data section (as we have not specified it as const). ”

    String literals are const by default. Compiling a demo dll and using “dumpbin /ALL” to inspect the sections seems to confirm that this string data is stored in the .rdata section.

    The main point you make, that storage requirements are doubled, is still valid.