Reputation: 805
I'm writing a Cocos2D-X game where the player, enemies and other characters store their attributes in a CCMutableDictionary
, which is somewhat of a decorator class for std::map<std::string, CCObject*>
. A value in the dictionary can be accessed via the CCMutableDictionary::objectForKey(const std::string& key)
method.
Now, in a header file included by many of my .cpp files, I've got a few const char * const
strings for accessing values in the dictionaries, like this:
// in Constants.h
const char* const kAttributeX = "x";
const char* const kAttributeY = "y";
// in a .cpp file
CCObject* x = someDictionary->objectForKey(kAttributeX);
So, correct me if I'm wrong, but std::string
's copy constructor is being called and a temporary std::string
is on the stack every time I call one of the above objectForKey
methods using a const char* const
, right?
If so, I feel that it would be more efficient at runtime if those constant attribute keys were already std::string
objects. But how do I do that the right way?
Defining them in the Constants.h file like the following compiles fine, but I have a feeling that something just isn't right:
// in Constants.h
const std::string kAttributeX = "x";
const std::string kAttributeY = "y";
My apologies if this question has already been asked. I couldn't seem to find the exact answer I was looking for here on StackOverflow.
Upvotes: 19
Views: 31278
Reputation: 114705
Your second option causes each of the variables to be created in every translation unit (cpp file that includes the header) which will slightly increase code size as well as adding a bit of runtime cost (constructing all those string during launch and destructing them during process termination).
The solution suggested by Joachim works but I find declaring and defining variables separately to be a bit of a drag. I personally hate repeating myself, also I don't like saying the same thing over and over again...
I don't know of a good solution for this in C++ proper but the compilers I've worked with all support something like __declspec( selectany )
so that you can define the variable in the header file and only get one object instantiated (rather than one for each translation unit).
__declspec( selectany ) extern const std::string kAttributeX = "x";
(For why both extern
and const
see this answer).
You still have the drawback of paying the initialization price of all the global variables during process launch. This is acceptable 101% of the time (give or take 2%) but you can avoid this by using lazy objects (I've written about something similar here).
Upvotes: 4
Reputation: 409176
The code you wrote is perfectly fine, at least as you only #include
the Constants.h
file in only one source file. If you use the header file in multiple source files, you will have the same variables defined multiple times. The correct use of constants in header files are to split them into a header (Constants.h
) which contains the declarations of the variables, and a source file (Constants.cpp
) which contains the definitions of the variables:
The header file:
#ifndef CONSTANTS_H
#define CONSTANTS_H
extern const std::string kAttributeX;
extern const std::string kAttributeY;
#endif
The source file:
const std::string kAttributeX = "x";
const std::string kAttributeY = "y";
Upvotes: 33