0

Meyer's singleton class blueprint is declared in a header file temp.h. If temp.h is included in two seperate.cpp files then each one have its own blueprint and as static things are not visible to other modules(i.e *.o or *.cpp) hence each .cpp file should have its own object of temp class(means two instance of temp in the program). But i have checked it in the program, same instance is shared between both the .cpp files. I don't understand why?

//temp.h
class temp
{
  public:
    ~temp() {}

    void temp_func()
    {
      std::cout << "Inside temp_func" << "\n";
    }
    static temp& createInstance()
    {
      static temp ins;
      return ins;
    }
  priave:
    temp() {}
};

Another header file, without class instance(with builtin datatype)

//temp1.h
inline static int& createInstance()
{
  static int ins;
  return ins;
}

//another.cpp
#include "temp1.h"
void func()
{
  int &t = createInstance();
  std::cout << "t: " << t << "\n";
  t = 20;
}

//main.cpp
#include "temp1.h"
void func();
int main()
{
  int &temp = createInstance();
  temp = 10;
  std::cout << "temp:" << temp << "\n";
  func();
  std::cout << "temp:" << temp << "\n";
  return 0;
}

Output of program

temp:10

t: 0

temp:10

Naseeb Panghal
  • 159
  • 1
  • 11
  • With the Meyer's Singleton, your instance should be `static` inside of `createInstance`. Also you can return a reference instead of a pointer since the instance will never be null. – 0x5453 Jul 16 '19 at 15:20
  • i have edited the question as suggested. Although still intent of my question is same. – Naseeb Panghal Jul 16 '19 at 15:23
  • 2
    `static` has many different meanings... `static` globals are private to the translation unit. `static` locals are created the first time the function is executed. `static` methods are class-methods – king_nak Jul 16 '19 at 15:25
  • @king_nak, when temp.h is included in multiple translation units, does all the units share common static temp::createInstance function in the memory? – Naseeb Panghal Jul 16 '19 at 15:29
  • there is only 1 temp::createInstance method. the static only means that you don't need an object to call it! For different uses of static see: https://en.cppreference.com/w/cpp/keyword/static – king_nak Jul 16 '19 at 15:37

2 Answers2

2

Check this inline keyword explanation. Quoting:

There may be more than one definition of an inline function or variable (since C++17) in the program as long as each definition appears in a different translation unit and (for non-static inline functions and variables (since C++17)) all definitions are identical. For example, an inline function or an inline variable (since C++17) may be defined in a header file that is #include'd in multiple source files.

Your createInstance function is exactly that kind of function - since you've defined it within class definition, it's implicitly inline. Thus compiler will merge them all together as if they were only one. As a result your function will return the same ins object.

Note, that function must be inline, otherwise something else happens - you violate one definition rule, to be precise:

One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.

EDIT: in second case it's not about built-in type data, but about you moving createInstance function outside class. What it does? It changes meaning of static keyword you've added to function definition - now the function will be copied (instead of being shared or merged together, when linked), thus every translation unit gets its own copy of int ins variable. Remove static keyword:

//temp1.h
inline int& createInstance()
{
  static int ins;
  return ins;
}

and it works just fine:

temp:10
t: 10
temp:20
Radosław Cybulski
  • 2,952
  • 10
  • 21
  • Your answer suggests behavior would be different in `createInstance` would be a non-inline function. This is not correct, non-inline function will also behave the same way with regards to shared static objects. In fact, the whole emphasizes on `inline` is a red herring. – SergeyA Jul 16 '19 at 15:54
  • I understand your point about inline, it does sound logical. But behaviour is different with built-in data type. I have modified the question to add temp1.h. Here instance of variable `static int ins` is not common , rather different instances are used in both another.cpp and main.cpp translation units even though it is inline function in temp1.h – Naseeb Panghal Jul 16 '19 at 15:58
  • @SergeyA: Non inline function defined twice violates ODR (one definition rule). See this https://en.cppreference.com/w/cpp/language/definition - quoting "One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined." – Radosław Cybulski Jul 16 '19 at 19:45
  • @RadosławCybulski while your quote is correct, it is irrelevant here. Nobody was suggesting to define the non-inline function twice. – SergeyA Jul 16 '19 at 19:49
  • You wrote "non-inline function will also behave the same way with regards to shared static objects". This is not true, inline functions are merged, non-inline functions must be defined exactly once or bad stuff happens. – Radosław Cybulski Jul 16 '19 at 19:55
1

Yes, this is what is going to happen. Block-scoped static variables (often called function-level static), such as your static temp ins; inside createInstance behave very similar to global variables - i.e. they are shared across all translation units and are preserved until program terminates (there is a difference when it comes to beginning of their lifetimes, but we won't go there for now).

As a matter of fact, usually the underlying mechanism for generating code with regards to such static variables is extremely similar to the one used with usual global variables. You can even think of them as a global variable with a name prefixed with the name of the function (although it won't be exactly correct, it might steer your thought process in the right direction).

In this particular case, you have a static variable inside a (inline) function, and any translation unit which calls this function will end up sharing the same static variable.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • @RadosławCybulski, non-inline function will behave the same way with regards to shared objects. – SergeyA Jul 16 '19 at 15:53