Tuesday, January 6, 2009

[C++] Potential danger with global const objects

Its a common practise of most of us to use statements like the below for defining string constants for our applications.
const CString csSomeStr = "Some String"

Let me say the above declaration may eat your private bytes(VM Size) with out your knowledge. Suppose you have added the above global declaration statement in some header file and the same is,
- included in 10 cpp files then it will create 10 copies of the global constant objects (instead of 1 as we expect)
- if it is included in header files and those header files are included in some other files then the result will be more worse (the included header file will inherit the created copy characteristics for the const objects!!!).
Altogether the result will be that your module become heavy in terms of Private Bytes for no valid reason (even without using the declared global constants). One interesting thing is that your module will not even link successfully if you remove the const of the global variable and its header file is included in multiple files. After all let me say const objects will be created by calling constructor for the above case; csSomeStr will
allocate heap memory for the "Some String" and will be copied inside the constructor.
For confirming the above facts let me show you an example that you can try out through below steps,
1. Create an SDI application (say TestGlobalObj) using MFC Classwizard then build & execute, the VM Size may be approximately some
564 K
2. Now create a header file common.h with below content. Please note that we are not referring this object !
#ifndef _COMMON_H_
#define _COMMON_H_

const CString csTempStr[1024*1024] = {"Test string"};
#endif
3. Include the common.h in the View class header file (say TestGlobalObjView.h) now build & execute, VMSize may be approximately 10404 K
4. Now include common.h in the Doc class header file (say TestGlobalObjDoc.h) and build & execute, VMSize may be approximately 15326 K
5. You put a break point at the above declaration of the csTempStr and you can find that this will be executed twice and CString constructor will be called each time for initializing the object.
6. Now modify the common.h with below content and build & execute to find the memory well around
564 K
#ifndef _COMMON_H_
#define _COMMON_H_
const LPCTSTR csTempStr[1024*1024] = {"Test string"};
#endif

So from this you will be clear about the hidden danger on declaring constant global objects, (danger with very common global constant CString objects) Always prefer primitive data types for global constants where ever possible. If you find your module is consuming more start up memory than expected then check for the global constant objects and confirm primitive data types are used wherever possible and unwanted objects are not kept global and included in the header files.

No comments: