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.
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 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'm having a problem with initialization order of a const static string class member. Some code:
constants.h
class Constants
{
public:
// not used right now
Constants& getInstance();
const static std::string CONST_STRING;
};
constants.cpp
const std::string Constants::CONST_STRING = "my string";
Constants& Constants::getInstance();
{
static Constants c;
return c;
}
which is classic const static initialization (ignoring the getInstance). However, if I then try to use this constant elsewhere in another translation unit like this:
class OtherClass
{
public:
OtherClass()
{
// tried uncommenting next line
// Constants::getInstance();
std::string str( Constants::CONST_STRING );
std::cout << str;
}
}
OtherClass obj; // note global
the CONST_STRING is empty, i.e. it has been constructed but not initialized. I know that global initialization order is not defined across translation units and I'm guessing something like that applies here?
However, removing the commented out line that attempts to ensure that Constants is fully constructed before it is used (I don't believe it is needed but giving it a go....) still doesn't fix things.
Questions:
How can I ensure const static members are fully initialized before anyone tries to use them?
Is this the best C++11 way to have constants associated with a class? Is constexpr something that could be used here?
The initialization of globals within a translation unit is going to occur in hidden code within that translation unit. You can't control the order in which those bits of hidden code are going to be called.
Constants with basic data types can be initialized at compile time rather than run time, so this would work:
const char Constants::CONST_STRING[] = "my string";
Maybe this is what are you looking for:
const std::string & GetConstantsString(){
static const std::string CONST_STRING = "My string";
return CONST_STRING;
}
As #AndreyT pointed out, literal type const static only are allowed to have in-class initializers so my option #1 will not work
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.
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++