C++ static const and initialization (is there a fiasco) - c++

I am returning to C++ after a long absence and I am stumbling a little over my understanding of the fairly well known static initialization problem.
Let's say I have a simple class Vector2 as given below (note that I am aware that x and y should be private with getters and setters, these have just been omitted for brevity):
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {};
float x,y;
}
Now, if I want to specify a static const member to represent a Vector2 with x and y set to 1, I am unsure on how to proceed - will static const members fall foul of the static initialization problem or will the act of making them const mean they are ok? I am toying with the following possibilities:
Possibility 1:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2 ONE;
float x,y;
};
// .cpp
const Vector2 Vector2::ONE = Vector2(1.f, 1.f);
Possibility 2:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2& getOne();
float x,y;
private:
static const Vector2 ONE;
};
// .cpp
const Vector2 Vector2::ONE = Vector2(1.f, 1.f);
static const Vector2& Vector2::getOne() {
return ONE;
}
Possibility 3:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2& getOne();
float x,y;
};
// .cpp
const Vector2& Vector2::getOne() {
static Vector2 one(1.f,1.f);
return one;
}
Now, my preferred way to write this would be as in possibility 2, just because it is a more comfortable syntax for me. However, if I call the getOne() method from another static method in another class am I going to risk crashing and burning? As I say, it is because I am using a static const rather than a plain static that I am asking this question as I have found much on plain static class member issues, but nothing on const static issues.
I suspect that I gain nothing by the fact that I am using static const and will need to go with Possibility 3 to be safe, but I just want to ask in case someone can shed some light on this for me.
I realise I am probably opening myself up to a slew of links pointing to exactly what I am asking, but I have looked and not found before posting this.
Any help will be gratefully appreciated.

All of them, except possibility 3, suffer from the static initialization order fiasco. This is because your class is not a POD. In C++0x, this problem can be solved by marking the constructor constexpr, but in C++03 there is no such solution.
You can remove the constructor to solve the problem in C++03, and initialize using
const Vector2 Vector2::ONE = { 1.f, 1.f };
This is initializing a POD, and all initializers in the list are constant expression (for the purpose of static initialization). The intialization of them happen before any code is run that might access it before being initialized.
3.6.2:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place.
8.5.1/14:
When an aggregate with static storage duration is initialized with a brace-enclosed initializer-list, if all the member initializer expressions are constant expressions, and the aggregate is a POD type, the initialization shall be done during the static phase of initialization (3.6.2); otherwise, it is unspecified whether the initialization of members with constant expressions takes place during the static phase or during the dynamic phase of initialization.

Please note that possibility 3 is not thread safe.
See for example "C++ scoped static initialization is not thread-safe, on purpose!" at http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx

Related

const declaration inside the class

to avoid complicated linker rules, C++ requires that every object has
a unique definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
I'm having hard time understanding this:
class Y {
const int c3 = 7; // error: not static
static int c4 = 7; // error: not const
static const float c5 = 7; // error: not integral
static const int c6 = 7;
};
How does const int c6 = 7; break following rule?
C++ requires that every object has
a unique definition.
And static const int c6 = 7; do not break it (enums too)?
Please also explain why static const float c5 = 7; is not allowed but static const int c5 = 7; is allowed?
A lot of these rules have been changing over time, so it really depends on the version of C++ you are using. Also, some of these may not be technically impossible, but the committee simply decided against them because they might be hard to implement, or are prone to errors. So you might not always get the most satisfying answer on why thing are the way they are.
Lets go over them one by one.
Const Member
class Foo
{
const int bar = 7;
};
This used to be illegal before C++11. Before that version you were only allowed to initialize static variables in their declaration. If you are still not on C++11, my condolences. More details can be found here.
Static Member
class Foo
{
static int bar = 7;
};
Another one that changed, but more recently. Before C++17 it was illegal to initialize non const static variables in their declaration. This has to do with the one definition rule. When the header containing this class is included in multiple translation units (.cpp files), which one should be responsible for initializing the value? This is why you have to place the definition somewhere in a single .cpp file.
After C++17 you are allowed to do this:
class Foo
{
inline static int bar = 7;
};
When you use inline like this it somehow figures out how to only initialize it once. More details can be found here.
Static Const Float Member
class Foo
{
static const float bar = 7.0f;
};
This has mainly to do with the unpredictability of floats when you run into floating point errors. An example:
class Foo
{
static const float bar = 0.1f;
};
Since 0.1f is impossible to represent in most floating point implementations, you won't get exactly 0.1f, but only something very close to it. This can then result in different behaviors on different systems that have slightly different implementations, causing your program to run differently depending on the system.
This gets even worse when the value is the result of a calculation, because (a*b)*c is not guaranteed to be the exact same value as a*(b*c), even though it might seem like they are.
But const static floats are still allowed when you define the value outside of the class, so technically it would all still be possible to implement. But the committee never did, probably because it would cause more problems than it would solve. This is also similar to why you are allowed to use integral types as template parameters, but not floats.
template <int i> class Foo {}; // Good
template <float f> class Bar {}; // Bad
However, the committee seems to have changed it's opinion somewhat, since we are now allowed to use floats with constexpr. So it can be done if you write this instead:
class Foo
{
static constexpr float bar = 7.0f;
};
Conclusion
All of these are actually possible in some form with the right version of C++ and the right syntax. Just keep in mind the potential issues described above, and you should be good to go.
Let go through it.
FIRST READ BELOW THEN COME TO CODE
class Y {
const int c3 = 7; // It's fine. If you write good constructor.
// static int c4 = 7; // error: not const as it is trying to initialize with object constructor which it shouldn't
static const float c5 = 7; // error: not integral as we can do it for integral type only. To correct this you can do.
static constexpr float c5 = 7; // we should use constexpr for literal type.
static const int c6 = 7; // it was fine as both types are same int and 6 where it was not the case in 1st case.
};
int main()
{
Y y;
}
First, learn these lines
a. When we create a const object of a class type, the object does not
assume its constness until after the constructor completes the object's initialization.
Thus, constructors can write to const objects during their construction.
So this will yield an error.
class Const {
public:
Const(int ii);
private:
int i;
const int ci;
};
ConstRef::ConstRef(int ii)
{ // assignments:
i = ii; // ok
ci = ii; // error: cannot assign to a const
}
**TO CORRECT THIS YOU SOULD DO**
Const::Const(int ii): i(ii), ci(ii) { } // this is how constructor should be
Let's discuss everything one by one.
Your fist member is already excellent. It should work fine as per my knowledge, and it's working for me. I think it's not working for you because your constructor is trying to initialize it in the constructor body, which you can't.
We must use the constructor initializer list to provide values for members that
are const, reference, or of a class type that does not have a default
constructor.
Let come to the static part
We say a member is associated with the class by adding the keyword static to its declaration.
The static members of a class exist outside any object.
static member functions are not bound to any object; they do not have
a this pointer. As a result, static member* functions* may not be declared as const, and we may not refer to this in the body of a static member. This restriction applies both to explicit uses of this and to implicit uses of this by calling
a nonstatic member.
IMP
Because static data members are not part of individual objects of the class type, they are not defined when we create objects of the class. As a result, they are not initialized by the class’ constructors. Moreover, in general, we may not initialize a static member inside the class.
So i think you got your second error reason. You are trying to initialize it with object constructor.
Let's go to the third one.
Ordinarily, class static members may not be initialized in the class body. However, we can provide in-class initializers for static members that have const integral
type and must do so for static members that are constexprs of literal type. The initializers must be constant expressions.
So.
static constexpr float c = 7; this is fine. You can check
I hope it' clear now. Let m know if you still got issues. Btw i skipped indirect concept too. But for depth understanding you need to learn about ``literal class`.

Initializing a constant in a class

I created a simple class for calculating the area of a rectangle.
class Rectangle
{
public:
Rectangle();
Rectangle(const double, const double);
class Invalid { };
double print_square();
private:
const double length, width;
inline bool check();
};
For width and length, I used constants, because they will not be modified in my class. In the constructor, I want to initialize them.
Why do I get an error in constructor body?
Cannot assign to non-static data member 'length' with const-qualified
type 'const double'
Constructor for 'Rectangle' must explicitly initialize the const
member 'length'
Error:
Rectangle::Rectangle(const double _length, const double _width)
{
length = _length;
width = _width;
if (!check())
throw Invalid();
}
OK:
Rectangle::Rectangle(const double _length, const double _width) : length(_length), width(_width)
{
if (!check())
throw Invalid();
}
I quite like the second option, but for a more convenient readability I do not want to write all the initialized variables in one line.
Is there a way to initialize a constant in the body of the constructor?
No, you can't.
This is because in your first example, since there is nothing in the initializer list, length and width will be default constructed, and then, in the body of the constructor, assigned the needed values _length and _width, which fails because they are constand already initalized.
In your second example, both variables are initialized without being default constructed. This approach constructs the const variables directly with the needed values, in one step.
Note that approach 2 uses only one step instead of two, so it is more efficient than what you want to do in approach 1. Because of that, it is generally good practice (even for non-const variables) to go with approach 2 whenever possible.
Is there a way to initialize a constant in the body of the constructor?
No.
You must use the initializer list (your second solution):
Rectangle::Rectangle(const double _length, const double _width) :
length(_length),
width(_width)
{
if (!check())
throw Invalid();
}
As already stated in a comment, you can put each variable initialization on a separate line

Why do I have to put this function static

I am trying t understand the Named Constructor Idiom in the example I have
Point.h
class Point
{
public:
static Point rectangular(float x, float y);
private:
Point(float x, float y);
float x_, y_;
};
inline Point::Point(float x, float y) : x_(x), y_(y) {}
inline Point Point::rectangular(float x, float y) {return Point(x,y);}
main.cpp
#include <iostream>
#include "include\Point.h"
using namespace std;
int main()
{
Point p1 = Point::rectangular(2,3.1);
return 0;
}
It does not compile If Point::rectangular is not static and I don't understand why...
In this context, the static keyword in front of a function means that this function does not belong to any particular instance of the class. Normal class methods have an implicit this parameter that allow you to access the members of that specific object. However static member functions do not have the implicit this parameter. Essentially, a static functions is the same as a free function, except it has access to the protected and private members of the class it is declared in.
This means you can call static functions without an instance of that class. Instead of needing something like
Point p1;
p1.foo();
You simply do this:
Point::foo();
If you tried to call a non static function like this, the compiler will complain, because non-static functions need some value to assign to the implicit this parameter, and Point::foo() doesn't supply such a value.
Now the reason you want rectangular(int, int) to be static is because it is used for constructing a new Point object from scratch. You do not not need an existing Point object to construct the new point so it makes sense to declare the function static.

static const in a struct, using constructor

I was looking for a method to initialize a static float inside a structure BUT using the constructor of the struct. In this site there are already solution to initialize the value but I was unable to find a solution that explicitly use the constructor.
The idea is the following:
struct test {
static const float a;
int b;
test(int bb, float a);
};
test::test(int bb, float aa) {
b=bb;
a=aa;
}
int main() {
int bval=2;
float aval=0.25;
struct test aaa(bval, aval);
return 0;
}
How to implement it correctly? Thank you for any advice.
You can't initialise it other than
const float test::a = something;
Outside the class (in a single compilation unit). However, you can do what you wrote and that will set the variable to the value you pass.
If you're wanting to set it only on the first time the constructor is entered, you can (but shouldn't) do something like
test::test(int bb, float aa){
static float _unused = (test::a = aa);
b=bb;
}
But that doesn't initialise it, it just assigns a value to it, and you'll still have to pass the variable to the constructor every time and nothing will be done with it (unless you give it a default value or something). That is a really terrible design though, it's probably better just to have a static function in the class to set the variable.
Static members are not associated with a particular instance, so they will only ever be initialised once. Constructors on the other hand are invoked on a per-instance basis, so it doesn't make sense to do what you're trying to do.
You can, on the other hand, assign a new value to static members in a constructor, as you're doing above, but you still have to actually initialise the static member outside the struct in the normal manner beforehand.
It's worth observing in passing that other languages (e.g. Java) have the concept of a static constructor for exactly this sort of thing - but C++ doesn't.
That said, you might find the following question interesting:
static constructors in C++? I need to initialize private static objects
You can't initialize a static const var inside constructor.
You should initialize at declaration
static const float a = 3.1416f;
Ensure you understand const keyword.
And should be integral.

How can static functions be useful?

I don't get all these keywords. Specially this one static. An example of how important it is and how it used would be wonderful.
Making a member function static allows you to call the function without creating the class object.
class MyClass
{
int i;
static MyClass *ptr;
static MyClass* getInstance()
{
if(NULL == ptr)
{
ptr = new MyClass();
}
return ptr;
}
};
MyClass* MyClass::ptr = NULL;
int main()
{
MyClass *ptr = MyClass::getInstance();
}
Check out the Singleton pattern for more information on how it can be helpful.
static member functions are just like regular functions.
class Sample
{
public:
static void DoWork()
{
cout << "Static Member Function"<< endl;
}
};
//access
Sample::DoWork();
Output:
Static Member Function
You can treat them just like regular functions, that means, you can pass them to other functions which accept only regular function as argument, like this:
typedef void (*Worker)();
void Fun(Worker worker)
{
//call here just like regular function
worker(); //note: class name is not needed even if you pass static member function!
}
//pass static member function!!
Fun(Sample::DoWork);
Output:
Static Member Function
There are multiple uses for the static keyword, it does different things based on where you use it.
http://msdn.microsoft.com/en-us/library/s1sb61xd.aspx
When you declare a variable or
function at file scope (global and/or
namespace scope), the static keyword
specifies that the variable or
function has internal linkage. When
you declare a variable, the variable
has static duration and the compiler
initializes it to 0 unless you specify
another value.
When you declare a variable in a
function, the static keyword specifies
that the variable retains its state
between calls to that function.
When you declare a data member in a
class declaration, the static keyword
specifies that one copy of the member
is shared by all instances of the
class. A static data member must be
defined at file scope. An integral
data member that you declare as const
static can have an initializer.
When you declare a member function in
a class declaration, the static
keyword specifies that the function is
shared by all instances of the class.
A static member function cannot access
an instance member because the
function does not have an implicit
this pointer. To access an instance
member, declare the function with a
parameter that is an instance pointer
or reference.
Static classes and class members are used to create data and functions that can be accessed without creating an instance of the class. The advantage is that you don't need to instantiate the class to use methods or properties.
An example of when to use a static class might be for utility functions such as converters (e.g. Fahrenheit to Celcius). This type function doesn't change irregardless of any object or data.
In C# you can call a static method like this:
double F, C = 0
// TempConverter converter = new TempConverter(); <-- NOT NEEDED FOR STATIC
F = TempConverter.CelsiusToFahrenheit("100.0");
C = TempConverter.FahrenheitToCelcius("212.0");
Here is how the static class and methods are defined:
public static class TemperatureConverter {
public static double CelsiusToFahrenheit(string temperatureCelsius) {
.. conversion code..
}
public static double FahrenheitToCelsius(string temperatureFahrenheit) {
.. conversion code..
}
}
There are two types of static functions: class/struct member, and non-member. I guess you're wondering about the former (as it's more confusing)...
static member functions
If we contrast four functions:
class X
{
....
int non_static_member_f(X& a) { ... }
static int static_member_f(X& a) { ... }
friend int non_member_friend_f(X& a) { ... }
};
int non_member_f(X& a) { ... }
And given:
X x, arg;
We can write:
x.non_static_member_f(arg) - x is an existing X object instance - made accessible via the this pointer. The function has full access to all private/protected/public static/non-static members of X for operations on x and arg.
X::static_member_f(arg) can be invoked with a single X argument - if the function didn't specify an X argument, then it could be called with no existing X objects. It has full access to all private/protected/public static of X, and can access any non-static members on arg.
non_member_friend_f(arg) has the same access as X::static_member_f(arg), but is not scoped inside X (i.e. you don't need to call it with the X:: prefix, Koenig lookup resolves differently).
non_member_f(arg) can only access the public members of arg, and has no special privileges.
For completeness: static non-member functions differ from non-static in having internal linkage, which means they're not callable from other translation units but won't clash with any same-named function in those translation units.
Static functions are very useful when implementing so-called Named Constructors.
Imagine a Point class which can be either constructed from rectangular coordinates (X/Y) or polar coordinates (radius and angle):
class Point {
public:
Point(float x, float y); // Rectangular coordinates
Point(float r, float a); // Polar coordinates (radius and angle)
// ERROR: Overload is Ambiguous: Point::Point(float,float)
};
int main()
{
Point p = Point(5.7, 1.2); // Ambiguous: Which coordinate system?
...
}
This can be solved very nicely using static functions which create Point objects; such functions are called named constructors since they act like a constructor (they produce a new object) but they can have a descriptive name:
class Point {
public:
// These static methods are the so-called "named constructors"
static Point rectangular(float x, float y) { return Point(x, y); }
static Point polar(float radius, float angle) { return Point(radius*std::cos(angle), radius*std::sin(angle)); }
// ...
private:
Point(float x, float y) : x_(x), y_(y) { }
float x_, y_;
};
Clients of the class can now use these named constructors to create readable, unambiguous code:
int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
}
Furthremore, named constructors can be used to make sure that objects of a class are always allocated with new (so that you know that you can always call delete on them). See FAQ [16.21] for more information.
static class member functions are useful:
For implementing the Factory Method Pattern
For implementing the Singleton Pattern
For loose decoupling of functions that may polute the behaviour of the class. ( Functions not necessarily members can be declared static... but even better they could be totally classic functions!) cf S.R.P.
Can be used as a function to be passed as a plain C function pointer so as to inter-operate with C code...
static functions are useful:
1. to avoid duplicate code redefinition while compiling. A static function will be redefined for each cpp unit it is included in.
And I think there are tons of other useful cases I don't remember of right now :-)
The answer from martona is a good overview of static. Relating to static members, I think Tony covers it pretty well.
The mental model I use when it comes to member functions is to consider how they might be modeled in 'C':
class A
{
public:
void mbr_1 ();
void mbr_2 () const;
void mbr_3 () volatile;
void mbr_4 () const volatile;
static void mbr_5 ();
};
Might be implemented as:
struct A { };
void mbr_1 (A * const this);
void mbr_2 (A const * const this);
void mbr_3 (A volatile * const this);
void mbr_4 (A const volatile * const this);
void mbr_5 ();
All the funcitons are members and so have appropriate 'access' to private members. The non static members have a 'this' pointer, and it is that which provides the access to a specific instances members. The static member doesn't have such a pointer and this is why we cannot access any non static members.