Setting a global variabel and reading it - c++

I'm creating a international program, so I need multiple languages in it. On the first screen I have a button with a flag on it, when clicking that flag, it knows the language and what file he needs to read.
For example: if you click the dutch flag it will read a file with Dutch sentences. It will fill the vector with the sentences, later on I use the vector to set the labels/buttons etc to the right language.
The thing is, im using multiple forms and I want to tell my other forms, the language = DUTCH, set the text in the labels/buttons into Dutch. But I need a global variable to work with that.
So my question is: How can I set a global variable?
I need a string thats just saying: "Dutch" or "English".
And I need a global vector for the lines of the file.
MainScreen.h:
extern std::string Global_Language;
extern std::vector<std::string> Global_VectorLanguage;
MainScreen.cpp:
std::string Global_Language = "English"; // since it's by default English
void __fastcall TMainForm::btnLanguageDutchClick(TObject *Sender)
{
TMainForm::SetLanguage("Dutch", "Nederlands.txt");
}
void __fastcall TMainForm::btnLanguageEnglishClick(TObject *Sender)
{
TMainForm::SetLanguage("English", "English.txt");
}
void TMainForm::SetLanguage(string a_Language, string a_fileName)
{
string line;
ifstream myfile;
Global_VectorLanguage.resize(100);
int Index = 0;
myfile.open(a_fileName.c_str());
if (myfile.is_open())
{
while(getline(myfile, line))
{
Global_VectorLanguage[Index] = line;
Index++;
}
myfile.close();
Global_Language = a_Language;
MainForm->Caption = Global_VectorLanguage[0].c_str();
lblHPI->Caption = Global_VectorLanguage[1].c_str();
lblPhoneNo->Caption = Global_VectorLanguage[2].c_str();
lblEmail->Caption = Global_VectorLanguage[3].c_str();
btnStart->Caption = Global_VectorLanguage[4].c_str();
btnStop->Caption = Global_VectorLanguage[5].c_str();
btnResetEmergency->Caption = Global_VectorLanguage[6].c_str();
gboxLicenseInfo->Caption = Global_VectorLanguage[7].c_str();
lblName->Caption = Global_VectorLanguage[8].c_str();
lblVersion->Caption = Global_VectorLanguage[9].c_str();
}
}
ManualScreen.cpp:
__fastcall TManualForm::TManualForm(TComponent* Owner)
: TForm(Owner)
{
if(Global_Language == "Dutch")
{
//set labels/buttons to Dutch
}
}

(What you are caring about is internationalization & localization and your operating system might have support for that, see e.g. locale(7), setlocale(3), gettext(3) etc... on Linux and with C++11 <locale> standard header)
You might declare a few global variables as extern in some header file and defile it in one source file.
E.g. in your header.h file a declaration:
extern std::string my_global_lang;
and in your localization.cc file a definition:
std::string my_global_lang{"English"};
However you often should prefer declaring a static variable inside some class (so called a class variable).
class MyLocalization {
static std::string global_lang;
/// etc...
};
Then use MyLocalization::global_lang
Having many global variables or static member variables is considered poor style. Generally, a program should have few global variables (less than you have fingers on one hand). You might prefer packing state into explicit instances of some class, perhaps declaring some singleton class ProgramState; and have one instance of it created early in your main; the QApplication class of Qt could inspire you.
I strongly recommend enabling all warnings & debug info when compiling (e.g. g++ -Wall -Wextra -g if using GCC) and reading some good C++ programming book and sites. We cannot teach you the basics of C++ programming (which is difficult) here.

You handle global variables just like you do local variables. The difference is mainly where the variable is declared. Just try something like:
#include <string>
std::string language = "English";
int main(void)
{
...
if (/*user changes language to Dutch*/)
{
if (language == "English")
language = "Dutch";
else
language = "English";
}
...
}

Related

C++: How to pass user input through the system without using global variables?

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

C++: function to append file, called within other functions

So, I am trying to log information about the status of the c++ project code in a text file. The program terminates unexpectedly, so I need to append the file as I go rather than storing info in an array along the way. I wanted to call the function to write to the file from within other functions, eventually in the other c++ files as well.
The code is a huge project that has many files and the "main()" technically exists in a separate file from all of the functions that are called throughout the function of the code (therefore not a useful file for me). My plan was to open the file in the setup() function, and then call the function within other functions along the way. Just in case I did not explain the setup of the code well enough, here is the link to the file I am trying to add to: https://github.com/cstracq2/ardupilot/blob/master/ArduCopter/ArduCopter.cpp
I have seen other notes on what may help, but I am not that familiar with c++ and I don't know what most of it means. From what I saw, this is one of the ways I tried, and it is failing to compile.
#include "<existing header>.h"
#include <fstream>
#include <iostream>
void log_data( ofstream &datafile, int value);
void <>::function1()
{ ....<stuff that was already there>
log_data( datafile, <value> );
}
void <>::function2()
{ ....<stuff that was already there>
log_data( datafile, <value> );
}
void setup()
{ ....<stuff that was already there>
ofstream datafile;
datafile.open("data_log_file.txt");
}
void log_data( ofstream &datafile, int value)
{
data_file << value << endl;
}
If there is any advice that you could give me, I would really appreciate it.
In your case I would suggest to use the Singleton Pattern. Here is an example of how you could do it:
class Logger
{
std::ifstream logF;
static Logger *s_instance;
Logger(std::string &path)
{
logF.open(path, std::ios_base::in);
}
public:
void log_data(int val)
{
logF << val << std::endl;
}
static void create_instance(std::string &path)
{
s_instance = new Logger(path);
}
static Logger *instance()
{
return s_instance;
}
};
Now you can just include the header with the class def and call something like:
Logger::instance()->log_data(<value>);
And do not forget to init the class before calling the static method (somewhere in main for instance):
Logger::create_instance(<path>);
Of course, you can just make it easier by hard-coding a value for your path, but if the path changes you'll have to re-compile everything.
Or just use something already implemented like log4cpp
Ah yes now that you mentioned the use of datafile in other function I see the error: The variable datafile is a local variable inside the setup function.
It should either be a member variable or possible a global variable.

Refer from 1 cpp file to another C++

I've got some problems with refering from 1 file to another.
I've got 2 VCL Forms:
- OpenPlotFile
- SelectElement
In my Plotfile I've got an openDialog:
void __fastcall TPlotFileForm::btn_fileselectClick(TObject *Sender)
{
AnsiString message;
//Dialog opties instellen
OpenDialog->Options << ofFileMustExist;
OpenDialog->Filter ="PPD files (*.PPD) |*.ppd |PLOT files (PLOT.*) | plot.*";
OpenDialog->FilterIndex = 2;
if (OpenDialog->Execute())
{
plotFile = OpenDialog->FileName;
Itxt_plotfile->Text=plotFile;
try
{
TFileStream *plotStream = new TFileStream(plotFile, fmOpenRead);
TStringStream *plotString = new TStringStream();
plotString->CopyFrom(plotStream, plotStream->Size);
FileBuffer = plotString->DataString;
delete plotStream;
delete plotString;
message = "Make your choice what to plot";
ListBox1->Items->Add(message);
message = "Default is everything, on insulation and with automatic weepholes at 1000 mm...";
ListBox1->Items->Add(message);
message = "Accept with the OK button...";
ListBox1->Items->Add(message);
btn_OK->Enabled=true;//Knop activeren nadat file is gekozen
}
catch(EStreamError &e)
{
ShowMessage(e.Message);
}
}
}
In this file I have a plotFile, this is the file directory. I want to get that value to another form: SelectElement
How I do it now is simple: I add AnsiString plotFile; to the OpenPlotFile.h
And I include OpenPlotFile.h in the SelectElement file.
#include "PlotFileScreen.h"
void __fastcall TSelectElementForm::FormShow(TObject *Sender)
{
element *ElementArray = new element[100];
ElementArray = GetElementInfo();
Itxt_plot_file->Text = plotFile;
Itxt_ordernumber->Text = ElementArray[0].ON;
Itxt_element_id->Text = ElementArray[0].MO;
Itxt_type->Text = ElementArray[0].SN;
Itxt_concrete->Text = ElementArray[0].el_concrete_height;
Itxt_Insulation->Text = ElementArray[0].el_iso_height;
Itxt_Length->Text = ElementArray[0].el_length;
Itxt_Width->Text = ElementArray[0].el_width;
Itxt_Weight->Text = ElementArray[0].el_weight;
Itxt_slabmark->Text = "";
Itxt_reinforce->Text = ElementArray[0].OW;
}
My program compiles and it works fine, but the odd thing is, When I debug, in both files it says: plotFile = NULL.
How can I solve this? Or how can I pass the plotFile to the other file without being NULL?
FYI: Global variables are ugly and should be avoided when possible. Encapsulation and abstraction are your friends. But to answer your question:
If plotFile belongs to your header file by declaring it via AnsiString plotFile; each translation unit gets its own copy. You need to define your variable in one *.cpp file and declare it as extern in your header.
From the C++ Standard:
3.5 Program and linkage
When a name has external linkage , the entity it denotes can be
referred to by names from scopes of other translation units or from
other scopes of the same translation unit.
So in your header file you have to place this:
extern AnsiString plotFile;
Define your variable in one cpp file:
AnsiString plotFile;
Don't use global variables for this, sooner or later you will get into trouble if you will always use this. One problem it causes is that you can use only once instance of your form because it is occupying your global variable.
There is a common solution to your problem that is I suppose identical on all platforms/systems/etc.. You have to pass your variable somehow to the form/dialog/etc class instance you want to show.
It looks like you are using Borland Builder C++, or Embarcadero. Proper way to solve your problem is to add AnsiString plotFile as a member variable of SelectElement form, and set it using accessor methods. Example code for it can be found here:
http://bcbjournal.org/articles/vol2/9810/Sharing_data_and_methods_between_forms.htm

Ensuring each struct has a unique ordinal number

I want to be able to create structs with each having a member that indicates the struct's (not the object's) order. There should be no run-time overhead, and I should be able to use the ordinal at compile-time.
The simples approach doesn't work because for some reason static variables don't work at compile-time:
int nextOrdinal() {
static int ordinal;
return ordinal++;
}
struct S1 {
enum ordinal = nextOrdinal();
}
struct S2 {
enum ordinal = nextOrdinal();
}
How the structs are created isn't important to me at this moment. The problem seems to be that it's not possible to retain a state at compile-time, am I correct?
--Inspired by Boost.units dimensional analysis.
There are no variables at compile-time (excepting the very special case of inside of a CTFE function)--everything must be constant. Further, allowing CTFE variables to go static and pollute the interpreted environment would be a pretty iffy design choice.
Part of the problem is that the compiler doesn't make any guarantees (to my knowledge) about the order of compilation of various code units and may even (in the future) be able to compile pieces in parallel. In general you need to treat compile-time programming as a very strict functional environment with small pockets of flexible mutability (inside CTFE functions). To ensure consistency, CTFE-able functions must be pure and "Ex­e­cuted ex­pres­sions may not ref­er­ence any global or local sta­tic vari­ables." http://dlang.org/function.html#interpretation
In short, I don't think there's any way to have the compiler store this state for you.
I don't know of a reliable way to do this, but if you want to order them based on their location in the source file you could do this:
import std.conv;
import std.stdio;
size_t nextOrdinal(size_t line = __LINE__)()
{
return line;
}
struct S1 {
enum ordinal = nextOrdinal();
}
struct S2 {
enum ordinal = nextOrdinal();
}
void main()
{
writeln(S1.ordinal);
writeln(S2.ordinal);
}
If you have multiple files that call nextOrdinal you could end up with struct definitions which have the same ordinal value. You might consider encoding the file name too:
size_t nextOrdinal(string file = __FILE__, size_t line = __LINE__)()
{
size_t res;
foreach (ch; file)
res += ch;
return res + line;
}

Removing namespace of type name in C++

In C++, when we use typeid to get type name of an object or class, it will show a decorated(mangled) string. I use cxxabi to demangle it:
#include <cxxabi.h>
#include <typeinfo>
namespace MyNamespace {
class MyBaseClass
{
public:
const std::string name()
{
int status;
char *realname = abi::__cxa_demangle(typeid (*this).name(),0,0, &status);
std::string n = realname;
free(realname);
return n;
}
};
}
int main()
{
MyNamespace::MyBaseClass h;
std::cout << h.name() << std::endl;
}
The output in gcc is:
MyNamespace::MyBaseClass
I need to remove MyNamespace:: from above string. i can remove them by string manipulating .
But is there a standard way with cxxabi or other libraries to do this or a clear solution?(At least portable between gcc and Visual C++)
There is no standard way to do this, period, because there is no standard way to do name mangling. How to represent names was intentionally unspecified. There is no ABI in the C++ standard. The function you are using, abi::__cxa_demangle, is a part of the Itanium C++ ABI. That function may or may not exist elsewhere.
As far as a way to do what you want using the Itanium C++ ABI, they intentionally do not provide such a capability.
I dont know if this would corresponds to your needs but i liked to mention about it.
There is something you can do to get the name of a class that you had write. And it may be considered as portable between gcc and Visual C++.
In GCC there is a magic variable named __FUNCTION__ as part of the gnu c language extensions, which treated as a variable, in C++. ( Treating it differs in C according to the GCC version. )
In Visual Studio there is a predefined macro which is in the same name and does the same job. Description is here.
You use __FUNCTION__ to get the name of the current function. So, to get the name of the class, may be you can use it in class constructor like this:
namespace MyNamespace
{
class MyBaseClass
{
public:
MyBaseClass(): myName(__FUNCTION__){}
string name() { return myName; }
private:
string myName;
};
}
So, you get "MyBaseClass" response if you call name() function of an instance of this class.
I investigated cxxabi and other c++ libraries for this issue and there isn't any pre-defined method to remove namespaces from that(at least in my googling).
I wonder why you dont want to manipulate the string?!
the best solution and fully portable (tested in gcc and vc++) is simipily below:
return n;
return n.substr(n.find_last_of(':')+1);
When you search n for a colon from last (= lastColorPos) and capture string from lastColorPos to end, it is definetly the class name.
If you just want to define a member-function which will return the string-name of the class, without the namespace, then I'm wondering why would you even use cxxabi or even __FUNCTION__ or anything else, other than simply doing this:
namespace MyNamespace
{
class MyBaseClass
{
public:
//make the function const as well
std::string name() const { return "MyBaseClass"; }
};
}
I mean you have full control on the implementation of the class, then why make it complicate when just one return-statement is enough? You can add another member function as well:
std::string fullname() const { return "MyNamespace::MyBaseClass"; }
Have a look at this somewhat related topic, maybe you will get more hints:
Reflect a class' inheritance tree in C++?
std::string removeNS( const std::string & source, const std::string & namespace_ )
{
std::string dst = source;
size_t position = source.find( namespace_ );
while ( position != std::string::npos )
{
dst.erase( position, namespace_.length() );
position = dst.find( namespace_, position + 1 );
}
return dst;
}
int main()
{
MyNamespace::MyBaseClass h;
std::cout << removeNS( h.name(), "MyNamespace::" ) << std::endl;
}