Instead of using #define or const, I usually define constants using class static methods as follows:
//AppConstants.h
#include <string>
class AppConstants{
public:
static int getMax();
static std::string getPrefix();
};
//AppConstants.cpp
#include "AppConstants.h"
int AppConstants::getMax(){
return 30;
}
std::string AppConstants::getPrefix(){
return "myprefix";
}
I do this usually when creating a mobile app, which I would like to save the compile time when each time change the value for testing. Is it a bad practice?
-
1that makes no sense. how exactly do you save compile time?BЈовић– BЈовић06/29/2017 07:53:37Commented Jun 29, 2017 at 7:53
-
2@BЈовић: When changing one of those constants, you only need to re-compile one file, instead of having to re-compile all files that reference one of the constants.Bart van Ingen Schenau– Bart van Ingen Schenau06/29/2017 09:51:48Commented Jun 29, 2017 at 9:51
-
1@BartvanIngenSchenau depends where you put the constant. If it is in the source file, then you do not need to recompile.BЈовић– BЈовић06/29/2017 11:33:01Commented Jun 29, 2017 at 11:33
-
3I don't know that what you are doing is bad practice, per-se. But I think calling them "constants" is bad practice. Specifically, getMax cannot be used as a case in a switch statement or to specify the size of an array. Therefore, getMax is not a "constant".OldFart– OldFart06/29/2017 18:26:10Commented Jun 29, 2017 at 18:26
2 Answers 2
Yes, and it's unnecessary too. You can declare constants in headers and define them in source files just like functions:
class AppConstants {
public:
static const int Max;
static const std::string Prefix;
};
const int AppConstants::Max = 30;
const std::string AppConstants::Prefix = "myprefix";
Especially in the case of the string, this has the advantage of not constructing a new one every time you access it.
It also has the disadvantage of being affected by C++'s unspecified global initialization order, so be careful if you use the constants from the initialization of other global variables/constants.
-
1While I mostly agree on this, why do you think it is a problem constructing a string every time?BЈовић– BЈовић06/29/2017 08:17:10Commented Jun 29, 2017 at 8:17
-
2It's an unnecessary heap allocation if the string is too long for SBO.Sebastian Redl– Sebastian Redl06/29/2017 08:21:16Commented Jun 29, 2017 at 8:21
-
it should allocate only if you modify the string - not otherwiseBЈовић– BЈовић06/29/2017 08:23:29Commented Jun 29, 2017 at 8:23
-
1Converting a string literal to a std::string allocates unless the std::string employs the Small Buffer Optimization and the string is short enough to fit. Copy-on-Write strings are not allowed in C++11, and CoW only applies to std::string's copy constructor anyway, not the one that takes a character pointer.Sebastian Redl– Sebastian Redl06/29/2017 08:34:03Commented Jun 29, 2017 at 8:34
-
6@Caleth
operator""s
is a convenient syntactical shortcut, but it doesn't magically get rid of the allocations. If you really want to avoid allocations, you have to useconst std::string& getPrefix() { const static std::string prefix = "myprefix"; return prefix; }
Sebastian Redl– Sebastian Redl06/29/2017 08:36:27Commented Jun 29, 2017 at 8:36
That's a good question. I would add to other answers.
It's better to write it this way and use 'class' keyword for real classes only to be explicit about your intentions:
namespace AppConstants {
static const int Max;
static const std::string Prefix;
};
I think, that even this would work:
#pragma once
namespace AppConstants {
const int Max;
const std::string Prefix;
};
Those constants will be static by default. But I am not sure if the last variant is a good practice.
But the fact is, if you want to make your code as fast as possible, making extra function calls is not what you would usually want. And since you didn't add 'inline' keywords, it is very likely there will be some.