When I have test data objects, or other static data objects such as SQL strings, I like to keep them out of application code. In Python, this is done with a separate source file and an import as shown below. How is static data organized and used C++?
(file: testdata.py)
x = Foo() (an object)
x.name = "Bar"
x.number = 123
..
(file: test.py)
import testdata.py
testObject1 = testdata.x
..
There are lots of possibilities. This also depends on what you're trying to do (e.g. do you want the values to be editable after compiling or only before compiling?
As for the later, you could use a separate translation unit.
In some header file:
extern const char *name;
extern const int number;
In one separate source file:
const char *name = "Bar";
const int number = 123;
However, you could do the class/struct approach, too:
Header file:
struct Foo {
const char *name;
int number;
};
extern const Foo Bar;
Source file:
const Foo Bar = {"Bar", 123};
The most flexible choice for connection strings etc. would be to create a settings file (with a format of your own choosing) and a class that can read the file, since this allows you to change the settings without recompiling the program.
For static data that you want to include in the code, you can use static class members:
// file.h
class Foo {
public:
static string getBar();
private:
static string bar;
};
// file.cpp
Foo::bar = "qwe";
static Foo::getBar() {
return bar;
}
You can put them in another file as well; extern data declarations in an header file, and the definitions in a .cpp file, like this:
// Foo.h
extern Foo afoo;
extern int anint;
// Foo.cpp
Foo afoo;
int anint = 0;
Then you can #include "Foo.h" wherever you want to use afoo and anint.
There are many ways to store data out of the source code.
For example, configuration files are stored in XML for example, though (fortunately) JSON has been gaining some grounds (not as much as I'd like to), and there are also custom formats.
Another example, for translation you might use gettext and store strings in .po files, and add new languages without recompiling.
It all works the same way, in the end:
you define a format for the file
you create a reader (and perhaps writer) procedure that converts between the file format and the in-memory format
you find a way to pass the file path to the program: fixed name in current directory, fixed name in home directory, command line argument, environment variable, etc...
If you wish to do it as you did in Python, you could also compile the resources into their own DLL and pull them at runtime while loading the symbols, changing the resources would only require re-compiling this one DLL.
Related
I have a C++ program that has several .hpp files with declarations of variables (most of them paths to a NFS filesystem) and .cpp files with the definitions of those variables.
In some of those variables, whose type is std::string, I need to build its content by appending some content passed as parameter in the main program. For instance:
File constants.hpp:
namespace constants {
extern std::string cudnn_version;
extern const std::string path_caffe_cuda;
extern const std::string path_caffe_cuda_cudnn;
}
File constants.cpp:
const std::string constants::path_caffe_cuda = "/nfs/apps/caffe/cuda";
const std::string constants::path_caffe_cuda_cudnn = constants::path_caffe_cuda + "/cudnn" + constants::cudnn_version;
The content of constants::cudnn_version is asked to the user in the main program as parameter and updated there. The problem is, when constants::path_caffe_cuda_cudnn variable must be built with the content of constants::cudnn_version variable, its content is still empty, so in some way the variable path_caffe_cuda_cudnn is evaluated before the constants::cudnn_version has the content passed by user.
How do you think I could fix the issue?
Thank you very much to everybody.
It could easily be done by using a function instead:
namespace constants {
extern std::string cudnn_version;
extern const std::string path_caffe_cuda;
inline std::string path_caffe_cuda_cudnn()
{
return constants::path_caffe_cuda + "/cudnn" + constants::cudnn_version;
}
}
As long as path_caffe_cuda_cudnn is not called until constants::cudnn_version have been initialized, then it will be okay.
I want to Use one globe variable in all cpp files.If one class of the cpp file changed the value,I want to access it from another class cpp file,which is the value that least modified by any other cpp class file.
str.h - global variable file
#ifndef MY_PROG
#define MY_PROG
extern char * myname;
#endif
class1.cpp
#include "str.h"
char * myname;
class class1
{
class1(){}
~class1(){}
void Setname1(char *name) { myname = name }
};
class2.cpp
#include "str.h"
char * myname;
class class2
{
class2(){}
~class2(){}
void setName(char *name) { myname = name }
};
class3.cpp
#include "str.h"
class class3
{
class3(){}
~class3(){}
char *GetData()
{
return myname;
}
};
main.cpp
#include "str.h"
int main()
{
class1 c1;
class2 c2;
c1.Setname1("XXXX");
c2.setname("YYYY");
class3 c3;
cout << c3.GetData;
}
when I execute the program, I need to get Last modified value that is "YYYY" .I am new to cpp, And also please tell me whether I used the extern keyword correctly.If not , please provide me the right procedure.
The essential in your problem is understanding the difference between declarations and definitions of variables (and types, functions etc. objects in C/C++)
extern char * myname; is a declaration. It makes myname visible to other pieces of code in the same file so that they can reference it.
char * myname; is a definition. Not only it makes myname visible, it also instructs the compiler to allocate space for it and to make its address known.
You can have as many declarations of the same variable in your code as you want, as long as they do not contradict each other. No so with definitions. If you define a thing two times, it would need to be assigned two addresses, and then how can other object files "understand" which address to use when referencing it? The same goes with the space allocated — what to do with the extra piece of it allocated? This is the error that you see.
To make the code work, have only one and exactly one definition of myname in exactly one file. It must not be a header file because it gets copied into multiple source files thus creating multiple definitions. It can be any other C++ file though.
In the rest of the files (or in a single header included in all of them) have multiple declarations of myname if it is referenced in a particular file. If not, you can omit it for a particular unit.
All this being said, it is considered to be a VERY BAD PRACTICE to communicate data between compilation units through global mutable shared variables. They make code a nightmare to debug and understand and impossible to parallelize. Nobody ever thinking getting money for the code they write should use them. Instead, the best approach would be to pass a mutable object as one of methods/functions argument. Details actually depend on the rest of your application.
c++ (not c++11)
Say i have 100 .cpp files in my project, which currently do some work.
All of those files currently include some globals.h file which i can edit easily.
I want each of those files to have its own instance of some object, and I also want that instance to have some unique ID of the file in which it is instantiated.
In addition, I want those objects to be created by a factory method, and I need the instances to have some way for a user to handle them - meaning they can't be anonymous.
In short - I need a way to generate unique IDs for all of the files in my project, i need the file to be able to access its own ID using the same name in all files, but also to be able to access the ID of a file externally in another "manager" file.
Here are options that don't work:
1.
Enum:
If I use an enum and give every file an enum ID, now I can't do this in globals.h:
static thePrivateInstanceInThisFile = theFactory.makeInstance(fileID);
because I need a different fileID in every file, and that was defined statically, and uniquely named using my enum.
2.
Class that counts its own instances
Define in globals.h:
class FileIDGiver{
private:
static int currentID;//initialize to 0 in cpp
int myID;
public:
FileIDGiver(){
myID = currentID++;
}
int getFileID(){
return myID;
}
}
static FileIDGiver theFileId;
static thePrivateInstanceInThisFile = theFactory.makeInstance(theFileId.getFileID());
This will give an ID to each static file instace which is unique to the file, but now it is not manageable externally to the file.
I thought about doing something like
globals.cpp
int file1ID;
int file2ID;
...
globals.h
extern file1ID;
extern file2ID;
...
file1.cpp
file1ID = theFileId.getFileID();
file2.cpp
file2ID = theFileId.getFileID();
...
and whenever a user needs to manage a file he would either use the file's ID variable, or create a new one in the above manner.
This would allow me to access each uniquely and automatically file ID externally.
The only problem I have with this is the line file1ID = theFileId.getFileID(); only executes in runtime, AFTER the line static thePrivateInstanceInThisFile = theFactory.makeInstance(theFileId.getFileID());.
which executes at compile time.
I can't figure out a good way to reverse this order, or maybe do a whole other mechanic.
Again - I need:
Automatically created file IDs
Unique file IDs (which are very very preferably numbers)
Usage of those IDs by the same variable name in all files (automatically, using a static variable definition in the globals.h file)
Ability to access a specific file ID manually by using another manually defined variable.
Please advise some good way to accomplish this
Thanks.
This sounds like a bad case of the static initialization order fiasco.
Here is a solution which uniquely assigns integer ids to each file, then generates a unique Instance by calling a factory function with the file's id, while ensuring that the Instance factory is initialized before its first use:
idgiver.h:
class IdGiver
{
int id;
public:
IdGiver() : id(0) {}
int getId() {return id++;}
};
IdGiver &getTheIdGiver();
idgiver.cpp:
#include "idgiver.h"
IdGiver &getTheIdGiver()
{
static IdGiver theIdGiver;
return theIdGiver;
}
factory.h:
class Instance
{
// ...
};
class Factory
{
// ...
public:
Factory() : {/*...*/}
Instance getInstance(int id) {/*...*/}
};
Factory &getTheFactory();
factory.cpp:
#include "factory.h"
Factory &getTheFactory()
{
static Factory theFactory;
return theFactory;
}
globals.h:
#include "idgiver.h"
#include "factory.h"
static int thisFileId = getTheIdGiver().getId();
static Instance thisFileInstance = getTheFactory().getInstance(thisFileId);
If you want to be able to access the static Instances of other files, then this cannot be done via an automatically generated id because the id generated for a file could change each time a new file is added, or every time it is compiled, or even on each execution. Therefore in this solution, each file manually defines its own persistent id similarly to example 1 in the question.
ids.h
enum FileId
{
File1, File2, File3
};
factory.h
#include "ids.h"
#include "instance.h"
class Factory
{
// ...
public:
Factory() {/*...*/}
Instance createInstance(FileId fileid) {/*...*/}
};
Factory &getTheFactory();
factory.cpp
#include "factory.h"
Factory &getTheFactory()
{
static Factory theFactory;
return theFactory;
}
idmanager.h
#include "ids.h"
#include "instance.h"
template<FileId id>
struct Manager
{
static Instance &getInstance(); // not defined
};
global.h
#include "idmanager.h"
#include "factory.h"
template <>
Instance &Manager<FILEID>::getInstance()
{
static Instance theInstance = getTheFactory().getInstance(FILEID);
return theInstance;
};
static Instance &getThisFileInstance()
{
return Manager<FILEID>::getInstance();
}
Usage is as follows: for each file requiring a static Instance object, place at the start
#define FILEID File1 // The FileId corresponding to this file
#include "global.h"
Then in any file,
The unique id is given by FILEID. (sorry it's a macro)
The static Instance of this file is obtained by getThisFileInstance().
The static Instance of any file is obtained by Manager<any_file_id>::getInstance().
This works by placing the implementation for an instantiation of the template Manager<FileId> in each file, each of which creates and returns that file's static Instance.
Advantages are persistence of ids, and zero run-time overhead: no need to dynamically assign ids, and the calls to Manager<file_id>::getInstance() are resolved at compile-time.
Also, the ids.h header can easily be generated by a script which scans the first line of each file for #define FILEID fileid, so the only maintenance left is remembering to write #define FILEID fileid.
You might modify your building procedure (e.g. your Makefile) to define some unique thing. E.g. you could compile your foo23.cpp file with something like (assuming GCC on some Linux system; adapt this to your compiler and OS and builder)
g++ -Wall -c -DBASENAME="$(basename foo23.cpp)" -DUNIQUEID=23
You could get the 23 for UNIQUEID using some shell script or whatever, e.g. an ad-hoc rule in your Makefile. Details depend upon your file naming conventions.
then use appropriately BASENAME and UNIQUEID in your C or C++ code (perhaps with dirty #if UNIQUEID==23 preprocessor tricks...).
So the idea is to generate the UNIQUEID in your build system and to pass it thru some preprocessor symbols. Details are OS, compiler, build-system specific.
You might also do some crude meta-programming by generating some C or C++ source or header file (perhaps using some awk script or some GPP or m4 preprocessing) in your building procedure.
(i have edited my original question to make it more understandable)
here is the prototype for the problem ....
//Txn.h ---this has a static variable, usable by the pgms including it.
class Txn
{
public:
static int i;
static void incr_int();
};
Txn::i=0;
//Txn.cpp
void Txn::incr_int() {i++;}
->produce LibTxn.so
//class1.cpp -> one of the pgm using the static var from Txn.h
#include Txn.h
Txn::incr_int()
-> produce class1.o, with LibTxn.so.
// class2.cpp ->another pgm using the static var from Txn.h
#include Txn.h
cout<<"Txn::i;
-> produce class2.o, by including LibTxn.so
-> .produce class3 (an exe) by using class1.o,class2.o. Since, both class1 and 2 has the statement "Txn::i=0" from "Txn.h", multiple declaration issue happens.
-> .If I remove the statement "Txn::i=0" from Txn.h, then "undefined reference" error appears.
-> .At high lvl, this problem is a kind of having a session variable, which should be assessible from any func in a exe. Those func can be in any obj files used to form the exe. I am fine for any sol, even without static. But I can't change the creation of different .o files (which are using this session var) and combining the .o to produce the exe.
It is hard to figure out exactly what the problem is if you cannot provide the real code, or at least an example which has the same problem as the real code.
However, most likely the root cause of the problem is that you are not only declaring, but also defining your class's static variable in the header file that contains the class definition.
This means that all the translation units (i.e. .cpp files) which include that header will contain a definition for the static variable, and when merging all the corresponding object files, the linker will eventually complain about that symbol being defined multiple times.
If this is the case, what you should do is to take the initialization of the static variable out of the header file which contains your class's definition and put it in one (and only one) .cpp file.
I tried to recreate the problem as you described, but it compiled just fine on my computer, and it is difficult to go further without seeing your code.
In the code below, the header tells (declares) every .cpp file that includes it about Foo::x, but Foo::x lives in (is defined in) Foo.cpp (and Foo.o)
foo.h:
class Foo {
public:
static int x;
};
Foo.cpp:
#include "foo.h"
int Foo::x;
main.cpp:
#include <iostream>
#include "foo.h"
int main(int argc, char *argv[]) {
Foo::x = 42;
std::cout << "Foo::x is " << Foo::x;
}
Yes. it worked by defining the static variable in .cpp.
Special thanks to Andy Prowl and iWerner.
My goal is to have global constants in a C++ game I'm working on (to represent some graphics info and the like). My current implementation is to toss them all in a .h and include them everywhere. This works, except that every time I change a setting, the entire code base must be recompiled.
So, my next idea was to toss them in some configuration txt file and parse them in, that way no code is actually changed when settings change. The parser was simple enough, and I could put the values into the constants, but because the parser was a code block, the constants were no longer global.
Is there a good way to solve this? Perhaps some way to make them global despite being in a block or some way to avoid recompiling everything when changing settings?
The way I used solve this is to put the variables in a separate global namespace, which is in a header file named something like config.h, then include that file everywhere.
// In config.h
#ifndef CONFIG_H
#define CONFIG_H
namespace config
{
extern int some_config_int;
extern std::string some_config_string;
bool load_config_file();
}
#endif
Then in a source file, you define the variable and also set them to a default value. This source file also have the code to load the variables from your configuration file.
// In config.cpp
namespace config
{
int some_config_int = 123;
std::string some_config_string = "foo";
}
bool config::load_config_file()
{
// Code to load and set the configuration variables
}
Now in every source file you need the configuration variables, include config.h and access them like config::some_config_int.
However, there is no "proper" way of solving this, all ways that work are proper in my eyes.
Another way to do this would be to create a singleton class.
#include <fstream>
#include <map>
#include <string>
class ConfigStore
{
public:
static ConfigStore& get()
{
static ConfigStore instance;
return instance;
}
void parseFile(std::ifstream& inStream);
template<typename _T>
_T getValue(std::string key);
private:
ConfigStore(){};
ConfigStore(const ConfigStore&);
ConfigStore& operator=(const ConfigStore&);
std::map<std::string,std::string> storedConfig;
};
Here the configuration is saved in a map, meaning as long as parseFile can read the file and getValue can parse the type there is no need to recompile the config class if you add new keys.
Usage:
std::ifstream input("somefile.txt");
ConfigStore::get().parseFile(input);
std::cout<<ConfigStore::get().getValue<std::string>(std::string("thing"))<<std::endl;
What about creating functions that return your constants that you can specify in a .cxx file? For example:
// foo.h
const int BAR();
// foo.cxx
const int BAR() {
return 10;
};
put only the declarations in head file and put the definitions in a cpp file. then you change the definitions in cpp file will not cause all code recompiled