Best way to design this code? - c++

I have a log function which takes a parameter, which prints out the name of some HW
logEvent("LOG THIS HW select = %s", NAME[selection]);
To determine what to print I have:
const char* NAME[] =
{
"A"
"B"
}
This was in the header but then I got multiple implementations problems, I want this to be accessed by many files. How can I put this kind of data in a header?

You put a declaration in the header:
extern const char* NAME[];
and put the definition in one cpp file:
const char* NAME[] = {"A", "B"};

Adjust logEvent so selection is passed as a parameter. You can then keep the string table local to that function.

Related

Which is one better for static const char* or static const string for declaring static variables

I am developing cross-platform C++ library. I wanted a better way of defining my string constants which will be used throughout the program. Which one is better static const char * or static const std::string?
Does constexpr make any of them better over the old declaration?
static const char *str = "hello world";
vs
static const string str = "hello world";
Why I need this:
My program might have to initialise a lot of static variable of string literals type before starting app. And i can't get away with static variables because they are used in the entire file. If i have to increase the performance, but reducing time of static variable initialisation. Ideally i would want most of things to happen at compile time rather than runtime. which one would be better choice?
Usually, std::string is good but in any case it depends on what you want to do. There is no absolute silver bullet here. std::string has a constructor and will call new/malloc for example (when SSO small string optimization can't be applied). If this is undesirable for any reason, go with const char*.
It depends also on where it 's to be used. If this is a HWND window title for example and the main use is with Windows API functions, it won't differ if you use std::string's c_str() method all the time.
All this is to advise that there is no 100% preference for one or another.
The usage or not of static is a different discussion.
It will depend on what you do with these variables. For example, take a look at this:
void do_stuff(std::string const&);
void stuff() {
while(/* some condition */) {
do_stuff(constant); // very hot loop
}
}
Let's take the two ways of defining the constant variable:
constexpr auto constant = "value"; // (1)
auto const constant = std::string{"value"}; // (2)
In the case of the hot loop, if you take (1), it will create a string each time. If the string value it long enough, it can cause allocation. Then (2) is better for that case.
On the other hand, if you refactor your code to something like this:
void do_stuff(std::string_view);
void stuff() {
while(/* some condition */) {
do_stuff(constant); // very hot loop
}
}
Then your program will be much faster with (1), since no dynamic allocation will occur. Your program will refer to the original read only data of your program.
With modern C++ I would use std::string_view.
If you do need it to be std::string then the best option is to define it as a static local variable in a function, so it is lazily initialized upon the first request.
/* inline or not */
std::string const& get_that_string() {
static std::string const str { "value" };
return value;
}
Unless there are known problems in your specific code base with using std::string, I strongly suggest using std::string.
static std::string const str = "hello world";
In general you should prefer std::string over char*. static has nothing to do with it.

How do I load custom "const" variables from a config file in C++?

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 want to call my function with string parameter

void GenerateDecryptedData("/home/merve/merve.enc", "/home/merve/merve.dec","dEneMe!1234");
I want to call my function like dEneMe!1234.
void GenerateDecryptedData(const char* pathToEncryptedFile,
const char* pathToDeccryptedFile,
std::string Pwd);
But when I wrote the function prototype like this, I'm taking string has not been declared- error! How can I take my password in string type?
You need the string header at the top of your source file: #include <string>. I'd consider Googling error messages more often. :)
string header - http://www.cplusplus.com/reference/string/
cstring header - http://www.cplusplus.com/reference/cstring/
What's wrong with:
void GenerateDecryptedData(const char* pathToEncryptedFile, const char* pathToDeccryptedFile, const char* Pwd);

Proper way to do const std::string in a header file?

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).

Qt tr does not seem to work on static constant members?

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));