We have a rather large project that defines static const std::strings in several places to be used as parameter names; some of them need to be concatenated during static initialization:
foo.h:
struct Foo {
static const std::string ParamSuffix;
};
foo.cpp:
const std::string Foo::ParamSuffix = ".suffix";
bar.h:
struct Bar {
static const std::string ParamPrefix;
};
bar.cpp:
const std::string Bar::ParamPrefix = "prefix";
baz.h:
struct Baz {
static const std::string ParamName;
};
baz.cpp:
const std::string Baz::ParamName = Bar::ParamPrefix + Foo::ParamSuffix;
The problem is obviously the "static initialization fiasco" as it is undefined in which order the static const members are initialized.
I dislike the usual solution, i.e. replace all these variables by functions, because
There's a lot of these variables, i.e. a lot of code changes
The concatenations require special functions, which makes the code base inconsistent and even more ugly
I currently cannot use C++11, which would make things easier with its constexpr feature (I think).
The question is: Is there any trick that would allow me to concatenate static const std::strings (or wrapper objects or whatever) to initialize another static const std::string?
The question is: Is there any trick that would allow me to concatenate static const std::strings (or wrapper objects or whatever) to initialize another static const std::string?
No trivial ones, other than the one you dislike: create functions for the static strings.
There are non-trivial alternatives though (e.g. replace all your hard-coded strings with a string container/string map and load the map on application start-up).
My recommendation though would be to go with static functions (the solution you rejected).
Why do you think that std::string const is in any way special? (hint: it is not) Even if you could use C++11's constexpr it wouldn't help because you can't make std:strings constant expressions (they may need to allocate memory which isn't a viable constant expression). You could deal with a string-like class used for constexpr that could be made to convert to std::string but I'm not sure if these could be concatenated to produce a new constexpr.
What you maybe able to do is to extract those strings you need to use as part of a concatenation and provide their value as macro. String literals (which have type char const[N] for a suitable N) can be concatenated by simply placing them next to each other:
// foo.h
#define FOO_PARAM_SUFFIX ".suffix"
struct Foo {
static const std::string ParamSuffix;
};
// foo.cpp:
std::string const Foo::ParamSuffix(FOO_PARAM_SUFFIX);
// bar.h:
#define BAR_PARAM_SUFFIX "prefix"
struct Bar {
static std::string const ParamPrefix;
};
// bar.cpp:
std::string const Bar::ParamPrefix(BAR_PARAM_SUFFIX);
// baz.h:
#include "foo.h"
#include "bar.h"
#define BAZ_PARAM_NAME BAR_PARAM_PREFIX FOO_PARAM_SUFFIX
struct Baz {
static std::string const ParamName;
};
// baz.cpp:
#include "foo.h"
#include "bar.h"
std::string const Baz::ParamName(BAR_PARAM_PREFIX FOO_PARAM_SUFFIX);
I would guess that BAZ_PARAM_NAME isn't used elsewhere in which case it also doesn't have to be defined: it is defined just to show it can be done. The initialization of Bar::ParamName assumes that BAZ_PARAM_NAME isn't defined.
When the text is not dependent on another variable, you might consider changing the type from const std::string to a const char array ala const char param_prefix[] = "prefix"; - there may well be less forced change to client usage, but that could hide new temporary std::strings having to be (or unintentionally being) created each time they're used.
Check your system, but you can almost certainly safely use those const char variables in the construction of other std::string constants - but you're out of luck for necessarily-std::string dependencies on other std::strings.
If it's too hard to untangle the existing values into can-be-const-char and std::strings that only depend on const-chars, or that just doesn't cover enough of your cases, then wholesale modifications to every constant are worth pursuing.
The appeal of wrappers is that you can keep the type and semantics of usage the same. To do that, you'll need to replace all these runtime-initialised strings with your own type that coordinates two central lists: - initialised objects, and waiting objects. An observer pattern is appropriate, or you could e.g. register a list of callbacks and complete initialisation by looping in main() calling them until they all indicate success: if at least some of the object initialisation is known to be static then that could allow one object to test another's initialisation status, which would avoid having to have constructors register their completion.
If it's possible with the help of smarter source code modifying tools (e.g. awk) - it may be better to simply change the constants to be cleanly returned by functions.
Related
So I'm currently working on a school-project with C++, which I'm not really familiar with.
I would like to create a class, containing all my constants (string,int,double,own classes)
I was trying this, which has always worked for me in Java:
class Reference {
//Picture-Paths
public:
static const std::string deepSeaPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string shallowWaterPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string sandPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string earthPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string rocksPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string snowPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
};
In C++, however, I get the following error:
Error C2864 'Reference::Reference::earthPath': a static data member with an in-class initializer must have non-volatile const integral type bio-sim-qt e:\development\c++\bio-sim-qt\bio-sim-qt\Reference.hpp 16 1
So is there any way for me to store for example String-Constants like this?
If yes, is there even a better way to do it? If no, is there another way (#define?) ?
In C++17, the recommended way of defining string constants if by using an inline constexpr std::string_view. Example:
namespace reference
{
inline constexpr std::string_view deepSeaPath{R"(something)"};
// ...
}
This is great because:
std::string_view is a lightweight non-owning wrapper that can efficiently refer to string literals without any additional costs.
std::string_view seamlessly interoperates with std::string.
Defining the variables as inline prevents ODR issues.
Defining the variables as constexpr makes it clear to both the compiler and other developers that these are constants known at compile-time.
If you do not have the luxury of using C++17, here's a C++11 solution: define your constants as constexpr const char* in a namespace:
namespace reference
{
constexpr const char* deepSeaPath{R"(something)"};
// ...
}
You should declare your data members in your header file, but the definitions should be placed in the source file, like this for example:
const std::string Reference ::earthPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
Read more in: Static Data Member Initialization.
PS: Classes do not use to expose into public scope their data members. Getter and Setter functions are used instead, while the data members are not in public scope. If all you need is your data members, then a namespace could be a better design choice, than a class.
I wish to have a class in my program that directly takes the Command Line arguments from the main method. I want some of this information to be Constant to the Class, but also dependant upon the Command Line arguments that were entered.
I have read the detailed answer here:
C++ defining a constant member variable inside class constructor , however I am still a little confused...
main.cpp:
#include "Launcher.h"
int main(int argc, char *argv[]) {
Launcher launcher(argc, argv);
// do other stuff with launcher
return 0;
}
Launcher.h:
#ifndef LAUNCHER_H
#define LAUNCHER_H
#include <string>
#include <vector>
class Launcher {
public:
Launcher(int, char *[]);
private:
const int argumentCount;
const std::vector<std::string> arguments;
static const std::vector<std::string> INIT_arguments(int, char *[]);
};
#endif
Launcher.cpp
#include "Launcher.h"
Launcher::Launcher(int inputCount, char *inputArguments[]) :
argumentCount(inputCount),
arguments(INIT_arguments(inputCount, inputArguments))
{}
Launcher::INIT_arguments(int inputCount, char *inputArguments[]) {
std::vector<std::string> argumentVector;
for (int i = 0; i < inputCount; i++) {
std::string currentArgument = inputArguments[i];
argumentVector.push_back(currentArgument);
}
return argumentVector;
}
(I understand that in this example there may be alternative methods to achieve the same results by not using an initializer lists. In other cases I've used complex functions to determine the const variable's value but chose this simple example to demonstrate the concept.)
My questions are:
Are there any problems with initializing a const member variable by using a static function(In the example above)?
Does anything change / are there any more problems if the function used to initialize the const variable is non-static?
Is there any difference between defining the function in the header file alongside its declaration versus how its been declared in the header file then defined in the source file? Are there any differences if it's static/non-static?
Unrelated to the general question but... Is there an easy way to pass the char *[] variable by reference or perhaps a more efficient way?
Are there any problems with initializing a const member variable by using a static function(In the example above)?
No. One could argue that such a local helper function that has little to do with your actual class could instead be outsourced into a helper/utility entity, maybe a free function (template) in an anonymous namespace or somewhere else (to make it testable).
Does anything change / are there any more problems if the function used to initialize the const variable is non-static?
Making it static ensures that the member function has nothing to do with any of the instances' state (same for free functions, obviously). I would definitely keep it that way for functions that are used to initialize state.
Is there any difference between defining the function in the header file alongside its declaration versus how its been declared in the header file then defined in the source file?
No. If you would make it a free function though, you need to take care of possible ODR violations, and at least mark it as inline.
Is there an easy way to pass the char *[] variable by reference or perhaps a more efficient way?
There is a more efficient way, i.e., not using the function at all and rely on the std::vector constructor (overload #4) that takes two iterators as arguments. Pointers to the same raw array are fine here, so you can just do:
Launcher::Launcher(int inputCount, char *inputArguments[]) :
argumentCount(inputCount),
arguments(inputArguments, inputArguments + inputCount) {}
Note also that Launcher doesn't seem to intend modifying the command line arguments. In this case, you don't have to copy the strings at all. Use a std::string_view instead (if C++17 is available) or just leave it as const char* (one nice thing about command line arguments is that you don't have to think about their lifetime).
Well, I know the functionality of const data member in a C++ class.
What I want to know is, the purpose of introducing a const data member in a class. Why someone will use that while writing a real software? What are the real-life usage of const data members?
Please give me a few real life examples with reasons.
EDIT :
I am not asking about static const data member.
I am asking for some real life use cases where each object will be having a different const value for same data.
You'd use a const data member for the same reason that you'd use any const object: for a value that may be arbitrarily initialised but then never changed.
A good rule of thumb is to denote something as const "by default", so you can picture plenty of reasons to use it in a class.
class User
{
User(const std::string& name)
: name(name)
{}
private:
/**
* User's name is an invariant for the lifetime of this object.
*/
const std::string name;
};
Can you leave out the const here? Yeah, sure. But then you may accidentally change name when you didn't mean to. The entire purpose of const is to protect against such accidents.
However, sadly, your class will not be assignable!
There are several cases. The most obvious one is a static const data member. These are used as scoped constants:
class Something {
static const int SOME_CONSTANT = 17;
};
Note that under C++11 and onward, constexpr usually makes more sense in those cases.
This defines a constant that is typed and scoped to the class' implementation. I suspect this was not what you were asking, however.
The more interesting use case is for values that are different between instances of the class, but constant across the class' lifetime.
For example, suppose you have a RAID implementation, where a configuration sets the stripe width. You do not know the stripe width at compile time, so the above construct will not help you. You do want the width to remain constant throughout the class' lifetime however (maybe your code doesn't know how to handle stripe width changes).
In those cases, marking the value const, and setting it in the constructor, can give you compile time guarantee that no one is changing this value.
You use it exactly the same as you would use a globally declared const, only you want it to only apply to the class you have defined it in. For example
class Character
{
public:
Character()
:
mCurrentHealth{TOTAL_HEALTH},
mCurrentMana{TOTAL_MANA}
{
}
// Define lose/gain health/mana functions
// for mCurrentHealth and mCurrentMana
private:
int mCurrentHealth;
int mCurrentMana;
// Constants
const int TOTAL_HEALTH = 100;
const int TOTAL_MANA = 50;
};
There are many other examples, but the main point is that we don't want TOTAL_HEALTH and TOTAL_MANA defined outside the class, because they won't be relevant.
I often need to define string constants associated with a class. Examples would be XML attributes, default filenames and many more.
In Java I would simply define something like
public static final String KEY = "attribute";
inside the class or interface.
In C++ the following would not compile:
class Example {
public:
static const std::string KEY = "attribute";
}
Instead, I would have to write:
class Example {
public:
static const std::string KEY;
}
const std::string Example::KEY = "attribute";
This is something I absolutely want to avoid because of its redundancy and verbosity.
The best solution I found so far is to use functions:
class Example {
public:
static std::string KEY() const { return "attribute"; }
}
This also provides some encapsulation and flexibility. However it might seem a bit weird to use a function just to define a constant.
So my question is, does this solution have major drawbacks and if yes, what are better alternatives?
In c++03, your best option is to use a function the way you are using, and this is awkward. The only thing is, why are you returning std::string and paying it's construction price, when you can return const char* const free of charge.
If, for some reason, you really have to have const std::string (again, it runs against my whole experience, so you might want to reconsider) following code works best in terms of efficiency (your current version calls std::string constructor on every call!):
class Example {
public:
static const std::string& key() {
static const std::string the_key = "That's my key!";
return the_key;
}
}
In c++11, you have several options, of which I find the best a constexpr:
class Example {
public:
static constexpr const char* const KEY = "TheKey";
}
The other option is in-place initialization of your const string, but why pay the price of it?
class Example {
public:
static const std::string KEY = "TheKey";
};
Whereas with Java, classes and their static members are loaded along with the class—which means that the class as a unit, or as part of a JAR, is replaceable—in C++ it doesn't go that way. If you stick things in headers, you pay the price of not being able to replace them until you re-compile everything that included them.
That's why the idiomatic—and most beneficial—way would be to indeed declare them in the header and provide the implementation where it belongs, in the translation units, which can be linked in to whatever other binaries. So consider readjusting your outlook (I moved from C# to C++ so I had this happen to me more than once).
But you don't have to go the way of strings at all. You can create enums, which is a much more elegant and type safe way to achieve this sometimes. With enums (and specifically enum classes), you can't just pass in the wrong string. You have to pass in one of a set of valid values.
As an example you could do:
class Example {
public:
enum class Attributes {
One,
Two,
// ...
};
}
And then, when it matters, and when you have local knowledge of what's what, you can map the enum values to actual strings or whatnot that the actual implementation requires.
You can define constructor of the class so that each time the class is used the constructor will automatically assign the value "attribute to the string"
class Example {
public:
static const std::string KEY;
Example()
{
KEY="Attribute";
}
};
I'd like to have a private static constant for a class (in this case a shape-factory).
I'd like to have something of the sort.
class A {
private:
static const string RECTANGLE = "rectangle";
}
Unfortunately I get all sorts of error from the C++ (g++) compiler, such as:
ISO C++ forbids initialization of
member ‘RECTANGLE’
invalid in-class initialization of static data member of non-integral type ‘std::string’
error: making ‘RECTANGLE’ static
This tells me that this sort of member design is not compliant with the standard. How do you have a private literal constant (or perhaps public) without having to use a #define directive (I want to avoid the uglyness of data globality!)
Any help is appreciated.
You have to define your static member outside the class definition and provide the initializer there.
First
// In a header file (if it is in a header file in your case)
class A {
private:
static const string RECTANGLE;
};
and then
// In one of the implementation files
const string A::RECTANGLE = "rectangle";
The syntax you were originally trying to use (initializer inside class definition) is only allowed with integral and enum types.
Starting from C++17 you have another option, which is quite similar to your original declaration: inline variables
// In a header file (if it is in a header file in your case)
class A {
private:
inline static const string RECTANGLE = "rectangle";
};
No additional definition is needed.
In C++11 you can do now:
class A {
private:
static constexpr const char* STRING = "some useful string constant";
};
Inside class definitions you can only declare static members. They have to be defined outside of the class. For compile-time integral constants the standard makes the exception that you can "initialize" members. It's still not a definition, though. Taking the address would not work without definition, for example.
I'd like to mention that I don't see the benefit of using std::string over const char[] for constants. std::string is nice and all but it requires dynamic initialization. So, if you write something like
const std::string foo = "hello";
at namespace scope the constructor of foo will be run right before execution of main starts and this constructor will create a copy of the constant "hello" in the heap memory. Unless you really need RECTANGLE to be a std::string you could just as well write
// class definition with incomplete static member could be in a header file
class A {
static const char RECTANGLE[];
};
// this needs to be placed in a single translation unit only
const char A::RECTANGLE[] = "rectangle";
There! No heap allocation, no copying, no dynamic initialization.
Cheers, s.
In C++ 17 you can use inline variables:
class A {
private:
static inline const std::string my_string = "some useful string constant";
};
Note that this is different from abyss.7's answer: This one defines an actual std::string object, not a const char*
This is just extra information, but if you really want the string in a header file, try something like:
class foo
{
public:
static const std::string& RECTANGLE(void)
{
static const std::string str = "rectangle";
return str;
}
};
Though I doubt that's recommended.
The class static variables can be declared in the header but must be defined in a .cpp file. This is because there can be only one instance of a static variable and the compiler can't decide in which generated object file to put it so you have to make the decision, instead.
To keep the definition of a static value with the declaration in C++11
a nested static structure can be used. In this case the static member
is a structure and has to be defined in a .cpp file, but the values
are in the header.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Instead of initializing individual members the whole static structure is initialized in .cpp:
A::_Shapes A::shape;
The values are accessed with
A::shape.RECTANGLE;
or -- since the members are private and are meant to be used only from A -- with
shape.RECTANGLE;
Note that this solution still suffers from the problem of the order of
initialization of the static variables. When a static value is used to
initialize another static variable, the first may not be initialized,
yet.
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
In this case the static variable headers will contain either { "" }
or { ".h", ".hpp" }, depending on the order of initialization created by the linker.
As mentioned by #abyss.7 you could also use constexpr if the value of the variable can be computed at compile time. But if you declare your strings with static constexpr const char* and your program uses std::string otherwise there will be an overhead because a new std::string object will be created every time you use such a constant:
class A {
public:
static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
foo(A::STRING); // a new std::string is constructed and destroyed.
}
To use that in-class initialization
syntax, the constant must be a static
const of integral or enumeration type
initialized by a constant expression.
This is the restriction. Hence, in this case you need to define variable outside the class. refer answwer from #AndreyT
possible just do:
static const std::string RECTANGLE() const {
return "rectangle";
}
or
#define RECTANGLE "rectangle"
You can either go for the const char* solution mentioned above, but then if you need string all the time, you're going to have a lot of overhead.
On the other hand, static string needs dynamic initialization, thus if you want to use its value during another global/static variable's initialization, you might hit the problem of initialization order. To avoid that, the cheapest thing is accessing the static string object through a getter, which checks if your object is initialized or not.
//in a header
class A{
static string s;
public:
static string getS();
};
//in implementation
string A::s;
namespace{
bool init_A_s(){
A::s = string("foo");
return true;
}
bool A_s_initialized = init_A_s();
}
string A::getS(){
if (!A_s_initialized)
A_s_initialized = init_A_s();
return s;
}
Remember to only use A::getS(). Because any threading can only started by main(), and A_s_initialized is initialized before main(), you don't need locks even in a multithreaded environment. A_s_initialized is 0 by default (before the dynamic initialization), so if you use getS() before s is initialized, you call the init function safely.
Btw, in the answer above: "static const std::string RECTANGLE() const" , static functions cannot be const because they cannot change the state if any object anyway (there is no this pointer).
The current standard only allows such initialization for static constant integral types. So you need to do as AndreyT explained. However, that will be available in the next standard through the new member initialization syntax.
Fast forward to 2018 and C++17.
do not use std::string, use std::string_view literals
please do notice the 'constexpr' bellow. This is also an "compile time" mechanism.
no inline does not mean repetition
no cpp files are not necessary for this
static_assert 'works' at compile time only
using namespace std::literals;
namespace STANDARD {
constexpr
inline
auto
compiletime_static_string_view_constant() {
// make and return string view literal
// will stay the same for the whole application lifetime
// will exhibit standard and expected interface
// will be usable at both
// runtime and compile time
// by value semantics implemented for you
auto when_needed_ = "compile time"sv;
return when_needed_ ;
}
};
Above is a proper and legal standard C++ citizen. It can get readily involved in any and all std:: algorithms, containers, utilities and a such. For example:
// test the resilience
auto return_by_val = []() {
auto return_by_val = []() {
auto return_by_val = []() {
auto return_by_val = []() {
return STANDARD::compiletime_static_string_view_constant();
};
return return_by_val();
};
return return_by_val();
};
return return_by_val();
};
// actually a run time
_ASSERTE(return_by_val() == "compile time");
// compile time
static_assert(
STANDARD::compiletime_static_string_view_constant()
== "compile time"
);
Enjoy the standard C++