0

I am trying to refactor our old code from c++98 to c++14. And the need to compile with both older gcc(c++98) and newer gcc(c++14). This is how our older code looks like (This is completely made up example, of our complicated code. The static consts fromthis class is used in another class).

// BankAccount.h
namespace bank {
class BankAccount {
 public:
    static const unsigned int account_number = 123456789;
    static const double balance = 0.0;
    BankAccount();
    ....
};
}

// BankAccount.cpp
namespace bank {
    BankAccount::BankAccount() {}
    ....
}

Looks like from c++11 only ints and enums are only allowed to initialise with in class declaration.

Question: By initialising the static const variables inside the class declaration like above does it avoid the static initialisation order fiasco ? Looks like with the above code, we never observed this static initialisation order problem, Should i be worried about the problem if i moved the static double and floats to .cpp file ?

BhanuKiran
  • 2,631
  • 3
  • 20
  • 36
  • Concerning `account_number` and `balance`, where do you see any order problem? These two variables are unrelated to each other. AFAIK, class members have to be initialized in the order declared but this is regardless in this case. It would be different when one static variable would depend on the other (e.g. the constructor of 2nd depending on the constructed 1st). – Scheff's Cat Apr 24 '21 at 12:24
  • Btw. are you sure that `account_number` and `balance` are proper candidates for being `static`? I'm rather not. It would result in that every instance of `BankAccount` would share the same members `account_number` and `balance` (with identical storage). (That's what a `static` class variable member does mean in C++.) If it would be my bank account I would immediately switch to another bank... – Scheff's Cat Apr 24 '21 at 12:27
  • @Scheff This is completely made up example, of our complicated code. The static consts from one class is used in another class . – BhanuKiran Apr 24 '21 at 12:49
  • @Scheff, I made a mistake, It has a const specifier. – BhanuKiran Apr 24 '21 at 12:54

1 Answers1

1

(Update: As the question has been changed to static const members)

By declaring them static const, it is safe for integer variables. In modern C++, there is no difference to declaring them as static constexpr. It is guaranteed by the language that you will not run into problems of accessing non initialized (or rather zero-initialized) numerical values.

For floating points like double, it should not compile unless you use constexpr. However, that is a feature which is not available on C++98. Without constexpr, you will get a compile error like that:

// gcc
example.cpp:6:25: error: ‘constexpr’ needed for in-class initialization of static data member ‘const double bank::BankAccount::balance’ of non-integral type [-fpermissive]
    6 |     static const double balance = 0.0;
      |                         ^~~~~~~

Or only with non-standard features:

// clang with -Wall -std=c++98
example.cpp:6:25: warning: in-class initializer for static data member of type 'const double' is a GNU extension [-Wgnu-static-float-init]
    static const double balance = 0.0;

(Old answer without declaring them const, but having them non-const)

Are you sure about the example? I don't think it will compile (both in C++98 and modern C++). You will get something like that unless you move the initialization out of the class definition:

// gcc
example.cpp:5:30: error: ISO C++ forbids in-class initialization of non-const static member ‘bank::BankAccount::account_number’
    5 |     static unsigned long int account_number = 123456789;
      |                              ^~~~~~~~~~~~~~
example.cpp:6:19: error: ‘constexpr’ needed for in-class initialization of static data member ‘double bank::BankAccount::balance’ of non-integral type [-fpermissive]
    6 |     static double balance = 0.0;
      |                   ^~~~~~~
// clang
example.cpp:5:30: error: non-const static data member must be initialized out of line
    static unsigned long int account_number = 123456789;
                             ^                ~~~~~~~~~
example.cpp:6:19: error: non-const static data member must be initialized out of line
    static double balance = 0.0;
                  ^         ~~~

If you move it out, then you may end up with the static initialization order fiasco. The values will start as being zero initialized and then it is depending on the linker when the real initialization code will be executed.

It would be safe if the variable could be declared as constants though.

Philipp Claßen
  • 41,306
  • 31
  • 146
  • 239
  • AFAIR, static order fiasco is a problem for symbols of distinct modules but not if the `static` variables belong to the same translation unit. (They should be defined in the order they appear in the source code.) [Static Initialization Order Fiasco](https://en.cppreference.com/w/cpp/language/siof): _The static initialization order fiasco refers to the ambiguity in the order that objects with static storage duration in **different translation units** are initialized in_ (Emphasize mine.) – Scheff's Cat Apr 24 '21 at 12:45
  • @philipp, I am sorry , I just edited the question to static const – BhanuKiran Apr 24 '21 at 12:53
  • @BhanuKiran I updated the answer. In a nutshell, with static const, you are safe. – Philipp Claßen Apr 24 '21 at 13:00
  • @PhilippClaßen Should I be worried about initialisation problem. if i refractor ` static const double` into cpp file like this ` const double BankAccount::balance = 1000.0` . ? – BhanuKiran Apr 24 '21 at 13:54
  • @BhanuKiran My understanding is that it will indeed introduce the problem, i.e. it will then depend on the order that the linker decides on. Maybe in your example, you can continue to use the GNU extension to support the old systems, at least on Linux systems it should be OK in practice (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11393). For modern compilers, constexpr is the way to go. Even if it is ugly, I could consider using a macro during the transition which resolves either to "const" (for GNU C++98) or "constexpr" (for C++11 and above). And hope that C++98 support goes way. – Philipp Claßen Apr 24 '21 at 14:33