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.
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";
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).
Related
I am having the problem, that my application can has a lot of user input which determines how the application will be run. The application is an in memory database system and the user could for example invoke the program with commands like '--pagesize 16384' (sets the memory page size to use), '--alignment 4096' (sets the memory alignment to use) or '--measure' (sets a flag to measure certain routines).
Currently I save all the user input in global variables which are defined as extern in a header file:
//#file common.hh
extern size_t PAGE_SIZE_GLOBAL;
extern size_t ALIGNMENT_GLOBAL;
extern size_t MEMCHUNK_SIZE_GLOBAL;
extern size_t RUNS_GLOBAL;
extern size_t VECTORIZE_SIZE_GLOBAL;
extern bool MEASURE_GLOBAL;
extern bool PRINT_GLOBAL;
extern const char* PATH_GLOBAL;
and in main source file:
#include "modes.hh"
size_t PAGE_SIZE_GLOBAL;
size_t ALIGNMENT_GLOBAL;
size_t MEMCHUNK_SIZE_GLOBAL;
size_t RUNS_GLOBAL;
size_t VECTORIZE_SIZE_GLOBAL;
bool MEASURE_GLOBAL;
bool PRINT_GLOBAL;
const char* PATH_GLOBAL;
int main(const int argc, const char* argv[]){
...
//Initialize the globals with user input
PAGE_SIZE_GLOBAL = lArgs.pageSize();
ALIGNMENT_GLOBAL = lArgs.alignment();
MEMCHUNK_SIZE_GLOBAL = lArgs.chunkSize();
RUNS_GLOBAL = lArgs.runs();
VECTORIZE_SIZE_GLOBAL = lArgs.vectorized();
MEASURE_GLOBAL = lArgs.measure();
PRINT_GLOBAL = lArgs.print();
std::string tmp = lArgs.path() + storageModel + "/";
PATH_GLOBAL = tmp.c_str();
...
}
I then include the header file common.hh in each file, where a global variable is needed (which can be very deep down in the system).
I already read a dozen times to prevent global variables so this is obviously bad style. In the book 'Code Complete 2' from Steve McConnell the chapter about global variables also stated to prevent global variables and use access routines instead. In the section 'How to Use Access Routines' he writes
"Hide data in a class. Declare that data by using the static keyword
(...) to ensure only a single instance of the data exists. Write
routines that let you look at the data and change it."
First of all, the global data won't change (maybe this is changed later but at least not in the near future). But I don't get how these access routines are any better? I will also have a class I need to include at every file where the data is needed. The only difference is the global data are static members accessed through getter functions.
(Edited) I also thought about using a global data Singleton class. But an object with ALL the global data sounds overkill since only a few global variables of the object are needed at its different destinations.
My Question: Should I just stick to the global variables? Are there better solutions, what am I missing? What are the best practices?
Edit:
If I would identify a few classes where the user input is needed the most, I could change the global data to member variables. What would be the best practice to pass the user input to these classes? Passing the data as parameters through the whole system down to the lowest layers sounds wrong. Is there are design pattern (thinking about something like a factory) which would be suited here?
How to pass user input through the system without using global
variables.
It is easy. Surprise, I created a class.
For a while, I called this class a travel case, because I considered it analogous to the needs of a suitcase during a trip. The TC_t is a non-standard container which held useful things for what is going on at your destination, and there is only one created, with references passed to any other objects that could use the information. Not global, in the strictest sense.
This TC_t is created in main() thread, while studying the command line options.
I recently wrote yet-another-game-of-life. User inputs included a) destination of output (i.e. a tty num), b) initial fill-pattern choices, c) 'overrides' for game board dimensions, d) test modes, including max speed, and vector vs. array options for cell behaviours.
The GOLUtil_t (Game Of Life Utility) (previously TC_t) includes methods that are useful in more than one effort.
For your question, the two typical globals I avoided are the a) gameBoard, and b) ansi terminal access.
std::cout << "accessing '" << aTermPFN << "' with std::ofstream "
<< std::endl;
std::ofstream* ansiTerm = new std::ofstream(aTermPFN);
if (!ansiTerm->is_open())
{
dtbAssert(nullptr != ansiTerm)(aTermPFN);
std::cerr << "Can not access '" << aTermPFN << "'" << std::endl;
assert(0); // abort
}
// create game-board - with a vector of cell*
CellVec_t gameBoard;
gameBoard.reserve (aMaxRow * aMaxCol);
GOLUtil_t gBrd(aMaxRow, aMaxCol, gameBoard, *ansiTerm);
This last line invoked the ctor of GOLUtil_t.
The instance "gBrd" is then passed (by reference) to the ctor of the game, and from there, to any aggregate objects it contained.
std::string retVal;
{
// initialize display, initialize pattern
GameOfLife_t GOL(gBrd, timeOfDay, fillPatternChoiceLetter, useArray);
std::string retValS = GOL.exec2(testMode);
retVal = gBrd.clearGameBoard(retValS); // delete all cells
}
// force GameOfLife_t dtor before close ansiTerm
ansiTerm->close();
Summary - No globals.
Every instance of any class that needed this info (where to output? what are dimensions?) has access to the GOLUtil_t for their entire lifetime. And GOLUtil_t has methods to lighten the coding load.
Note: because single output terminal, I used a single thread (main)
Your first refactor effort might be to:
a) remove the global classes,
b) and instead instantiate these in main() (for lifetime control)
c) and then pass-by-reference these formerly global instances to those non-global objects that make use of them. I recommend in the ctor(s).
d) remember to clean up (delete if new'd)
my environment: Ubuntu 15.10, 64 bit, g++ V5
I am experiencing the following issue, in my DLL project:
At the DLL side :
Inside the DLL I have declared a static vector as follows :
static std::vector<FilterProcessor::FilterInfo*> TableOfContents;
At DLL’s initialization time of static members, I am adding some entries to the above vector.
I have defined an extern “C” global function (getTocPointer()) which is returning a pointer to the vector, when it called from the client program.
extern "C" __declspec(dllexport) std::vector<FilterProcessor::FilterInfo*>* __cdecl getLibraryTOC();
At the client’s program side :
The DLL library is loaded without any problem
The address of getTocPointer() function is returned correctly to the client program, when the getProcAddress() function is called.
Indeed, when I am performing the debugging process in the DLL-side, the client program calls the above function and the execution process enters to it.
However, the vector has a zero size and, has no any contents which were added to it at initialization time. It seems it points to another vector object. . .
I can’t really understand what exactly goes wrong here.
The way of adding entries to this vector at initialization time, is the proper way?
If yes, what probably goes wrong when the client program calls the getLibraryTOC() function?
Thanks in advance
George
If that static global definition of the vector appears in a header file, then yes you do have multiple different vectors. Change the keyword static to extern to make the header file declare the vector rather than defining it, and then add exactly one definition in an implementation file.
Then, you may encounter the static initialization order fiasco. If the vector is defined in a different compilation unit than the code attempting to add entries to it, there's no guarantee that the vector object is alive yet. Attempting to use a vector whose constructor hasn't run is undefined behavior -- it might easily manifest as the constructor running afterward and setting the contents to zero length (as a default constructor should), but many other problems are possible.
You can avoid the SIOF by using a local static.
std::vector<FilterProcessor::FilterInfo*>& table_of_contents()
{
static std::vector<FilterProcessor::FilterInfo*> singleton;
return singleton;
}
In every location that would have accessed the global, including the initialization logic that fills the vector, and also your getLibraryTOC() exported function, call the accessor function instead.
That all is applicable to any C++ software having multiple compilation units. When you have a DLL, things get even more complicated, because the DLL and EXE are compiled and linked separately from each other, possibly with different settings, different compilers, or even entirely different languages. Sharing of complex objects across DLL boundaries is real trouble. If the DLL and EXE are always recompiled at the same time, it can work. But if you're trying to distribute the DLL for use by another party who writes the EXE code, the strong coupling will quickly become intolerable.
A better approach is to hide the library objects from the DLL boundary, and pass only primitive or OS-managed types across. For example:
#define DLLAPI __declspec(dllexport) __cdecl
extern "C" DLLAPI int32_t getLibraryTocCount()
{ return table_of_contents.size(); }
extern "C" DLLAPI BSTR getLibraryTocName(int index)
{ return ::SysAllocString(table_of_contents[index].name.c_str(); } // assumes std::wstring
// etc
The library I have implemented contains the following code (in a brief description) :
An Index class which implements the Table of contents of the library
A collection of audio filters named Filter01, Filter02 etc.
Index.h
struct LIB_SPECS Library_TableOfContents
{
static bool addTOCEntry(FilterInfo* Filter_Info); // add an entry to the TOC
static std::vector<FilterInfo*> TableOfContents; // TOC
};
/*-------------------------------------------------------------------
Called from the client program to return the pointer to TOC */
extern "C" LIB_SPECS std::vector<FlterInfo*>* __cdecl getLibraryTOC();
Index.cpp
/* Define / Initialize static variables */
std::vector<FilterInfo*> Library_TableOfContents::TableOfContents = {};
//=====================================================================
bool Library_TableOfContents::addTOCEntry(FilterInfo* Filter_Info)
{
Library_TableOfContents::TableOfContents.push_back(Filter_Info);
return false;
}
//======================================================================
std::vector<FilterInfo*>* getLibraryTOC()
{
return &Library_TableOfContents::TableOfContents;
}
For each Audio Filter in the library :
Filterxx.h
class LIB_SPECS Filterxx
{
public:
static struct FilterInfo
{
public:
std::string filterName;
std::string filterDescription;
// other filter info
FilterInfo(); // FilterInfo constructor
} Filter_Info;
virtual String doSomeWork(int AvatarId);
virtual void deleteFilter() = 0;
};
Filterxx.cpp
Filterxx::FilterInfo Filterxx::Filter_Info("Filterxx", “A filter description e.g. Low pass Filter ” ); //
FilterInfo::FilterInfo(std::string name, std::string description)
{
Filter_Info.filterName = name;
Filter_Info.filterDescription = description;
Library_TableOfContents::addTOCEntry(&Filter_Info);
}
// other filter functions
The getLibraryTOC() function, is called from the client program to get the table of contents in order to show it to the user.
As I said, indeed it is called by the client but, at the time of call, the table of contents seems to have a zero size.
I currently have a function which loads variables from a config file. It uses these to initialise a set of constant config variables.
// header file
namespace cfg {
extern const char *config_value;
}
// source file
namespace cfg {
const char *config_value;
}
bool load_config() {
cfg::config_value = load_config_line("config_value");
}
const char *load_config_line(const char *key) {
// read value from config.cfg...
}
This works pretty well. The problem is that now I want to reuse this code in several other projects, which means the constant values have to change. This means changing the config_value names in four different places each in the code. It also means I have several copies of essentially the same code to maintain in different projects.
Is there a way of setting different sets of constant values using the same code for the reading and parsing? Perhaps so that all I have to do is change the header file and it automatically finds those value names in the config file? The tricky part is that ideally the outward facing config values themselves should be constant and available at compile time (using a string to value map for example is undesirable, as I would prefer to have the compile time protection).
The solution here is to not use global variables, and instead have some settings struct which you explicitly initialize with values loaded from the file. The struct instance itself doesn't need to be const (you'll need to be able to load the values into it, unless you pass everything in on construction), but all access to it should be const. This last bit can be achieved by passing settings as e.g. a const settings& to wherever it is needed.
int main()
{
// Variant A: 2-step init
settings s;
s.loadConfigFile(filename);
// Variant B: 1-step init - can make instance itself const
const settings s(filename);
Thing worker(s); // Thing::Thing(const settings&)
worker.work();
}
Of course Worker can be anything your heart desires.
Note that settings itself needs no special constness whatsoever:
struct settings
{
std::string config_value;
}
It is the external const that guards access to the values contained within.
I have sort of a tricky problem I'm attempting to solve. First of all, an overview:
I have an external API not under my control, which is used by a massive amount of legacy code.
There are several classes of bugs in the legacy code that could potentially be detected at run-time, if only the external API was written to track its own usage, but it is not.
I need to find a solution that would allow me to redirect calls to the external API into a tracking framework that would track api usage and log errors.
Ideally, I would like the log to reflect the file and line number of the API call that triggered the error, if possible.
Here is an example of a class of errors that I would like to track. The API we use has two functions. I'll call them GetAmount, and SetAmount. They look something like this:
// Get an indexed amount
long GetAmount(short Idx);
// Set an indexed amount
void SetAmount(short Idx, long amount);
These are regular C functions. One bug I am trying to detect at runtime is when GetAmount is called with an Idx that hasn't already been set with SetAmount.
Now, all of the API calls are contained within a namespace (call it api_ns), however they weren't always in the past. So, of course the legacy code just threw a "using namespace api_ns;" in their stdafx.h file and called it good.
My first attempt was to use the preprocessor to redirect API calls to my own tracking framework. It looked something like this:
// in FormTrackingFramework.h
class FormTrackingFramework
{
private:
static FormTrackingFramework* current;
public:
static FormTrackingFramework* GetCurrent();
long GetAmount(short Idx, const std::string& file, size_t line)
{
// track usage, log errors as needed
api_ns::GetAmount(Idx);
}
};
#define GetAmount(Idx) (FormTrackingFramework::GetCurrent()->GetAmount(Idx, __FILE__, __LINE__))
Then, in stdafx.h:
// in stdafx.h
#include "theAPI.h"
#include "FormTrackingFramework.h"
#include "LegacyPCHIncludes.h"
Now, this works fine for GetAmount and SetAmount, but there's a problem. The API also has a SetString(short Idx, const char* str). At some point, our legacy code added an overload: SetString(short Idx, const std::string& str) for convenience. The problem is, the preprocessor doesn't know or care whether you are calling SetString or defining a SetString overload. It just sees "SetString" and replaces it with the macro definition. Which of course doesn't compile when defining a new SetString overload.
I could potentially reorder the #includes in stdafx.h to include FormTrackingFramework.h after LegacyPCHIncludes.h, however that would mean that none of the code in the LegacyPCHIncludes.h include tree would be tracked.
So I guess I have two questions at this point:
1: how do I solve the API overload problem?
2: Is there some other method of doing what I want to do that works better?
Note: I am using Visual Studio 2008 w/SP1.
Well, for the cases you need overloads, you could use a class instance that overloads operater() for a number of parameters.
#define GetAmount GetAmountFunctor(FormTrackingFramework::GetCurrent(), __FILE__, __LINE__)
then, make a GetAmountFunctor:
class GetAmountFunctor
{
public:
GetAmountFunctor(....) // capture relevant debug info for logging
{}
void operator() (short idx, std::string str)
{
// logging here
api_ns::GetAmount(idx, str);
}
void operator() (short idx)
{
/// logging here
api_ns::GetAmount(Idx);
}
};
This is very much pseudocode but I think you get the idea. Whereever in your legacy code the particular function name is mentioned, it is replaced by a functor object, and the function is actually called on the functor. Do consider you only need to do this for functions where overloads are a problem. To reduce the amount of glue code, you can create a single struct for the parameters __FILE__, __LINE__, and pass it into the constructor as one argument.
The problem is, the preprocessor doesn't know or care whether you are calling SetString or defining a SetString overload.
Clearly, the reason the preprocessor is being used is that it it oblivious to the namespace.
A good approach is to bite the bullet and retarget the entire large application to use a different namespace api_wrapped_ns instead of api_ns.
Inside api_wrapped_ns, inline functions can be provided which wrap counterparts with like signatures in api_ns.
There can even be a compile time switch like this:
namespace api_wrapped_ns {
#ifdef CONFIG_API_NS_WRAPPER
inline long GetAmount(short Idx, const std::string& file, size_t line)
{
// of course, do more than just wrapping here
return api_ns::GetAmount(Idx, file, line);
}
// other inlines
#else
// Wrapping turned off: just bring in api_ns into api_wrapper_ns
using namespace api_ns;
#endif
}
Also, the wrapping can be brought in piecemeal:
namespace api_wrapped_ns {
// This function is wrapped;
inline long GetAmount(short Idx, const std::string& file, size_t line)
{
// of course, do more than just wrapping here
return
}
// The api_ns::FooBar symbol is unwrapped (for now)
using api_ns::FooBar;
}
I'm working on translating our Qt gui at the moment.
I have the following code:
// header file
static const QString Foo;
// cpp file
const QString FooConstants::Foo = "foo";
// another cpp file
editMenu->addAction(tr(FooConstants::Foo));
This doesn't seem to work though.
That is, there is no entry in the .ts file for the above constant.
If I do this then it works:
// another cpp file
editMenu->addAction(tr("foo"));
However, this constant is used in many places, and I don't want to have to manually update each string literal. (if it were to change in the future)
Can anyone help?
Wrap your literal in the QT_TR_NOOP macro:
// cpp file
const QString FooConstants::Foo = QT_TR_NOOP("foo");
From the guide:
If you need to have translatable text completely outside a function, there are two macros to help: QT_TR_NOOP() and QT_TRANSLATE_NOOP(). They merely mark the text for extraction by the lupdate tool. The macros expand to just the text (without the context).
As Thomas mentioned, you have to use a macro.
The reason is that Qt doesn't know which strings to translate by default, it scans the files and looks for a set of patterns. One of them is tr("text"), but if you want to use a constant, you will have to mark it explicitly with QT_TRANSLATE_NOOP or QT_TR_NOOP when it's defined.
editMenu->addAction(tr(FooConstants::Foo));
I think your problem is that tr takes a char* argument, not a QString:
QString QObject::tr ( const char * sourceText, const char * disambiguation = 0, int n = -1 )
You could change the type of FooConstants::Foo, or convert it to a char* when you create the menu action, for example:
const QByteArray byteArray = FooConstants::Foo.toLatin1();
char *data = byteArray.data();
editMenu->addAction(tr(data));