Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Static Member variable and static member function resides in ????
Forum Updated to NodeBB v4.3 + New Features

Static Member variable and static member function resides in ????

Scheduled Pinned Locked Moved Unsolved C++ Gurus
22 Posts 7 Posters 5.0k Views 6 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Kent-DorfmanK Online
    Kent-DorfmanK Online
    Kent-Dorfman
    wrote on last edited by Kent-Dorfman
    #5

    In c++ a design that is sensitive to static order initialization is itself suspect, and shouldn't pass a reasonable code review. It's not the OS that initializes anything in a c++ elf or a.out image. it is typically a small linked in object called crt0.o and since the order of global/static initialization in c++ is undefined, it should never be relied upon, even if a particular platform is observed to behave a certain way.

    The well defined and verifiable work-around is the "constuct on first use idiom". None of which requires internal knowledge of program memory layout in c++.

    These kinds of discussions remind me of things like editing vtables in c++. There should never be a reason to do so, and in fact, the language specification doesn't even require their existence.

    Chris KawaC 1 Reply Last reply
    0
    • Kent-DorfmanK Kent-Dorfman

      In c++ a design that is sensitive to static order initialization is itself suspect, and shouldn't pass a reasonable code review. It's not the OS that initializes anything in a c++ elf or a.out image. it is typically a small linked in object called crt0.o and since the order of global/static initialization in c++ is undefined, it should never be relied upon, even if a particular platform is observed to behave a certain way.

      The well defined and verifiable work-around is the "constuct on first use idiom". None of which requires internal knowledge of program memory layout in c++.

      These kinds of discussions remind me of things like editing vtables in c++. There should never be a reason to do so, and in fact, the language specification doesn't even require their existence.

      Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by Chris Kawa
      #6

      @Kent-Dorfman said:

      These kinds of discussions remind me of things like editing vtables in c++. There should never be a reason to do so

      I disagree. It's not like "if it's not in C++ standard it doesn't exist". The hardware is hardware and doesn't care for high level languages. OSes rarely have C++ API only, so to leverage some fine grained features of these you sometimes need to rely on hardware/OS guarantees, not those of C++ standard.
      Sure, I'm not saying you should rely on static initialization order because there's just no guarantee at all, C++ or otherwise, but that's not what OP was asking and I don't see anything wrong in wanting to know how stuff works. I see that as a positive. Curiosity in programming is a good trait in my view, even if you don't necessarily immediately apply everything you're curious about. I think saying "you shouldn't be asking that" is a trait of bad teacher, not bad student.

      As an example - I wouldn't automatically take a question about undefined behavior as a sign that someone wants to exploit it, but rather someone trying to avoid it. Same here - asking about statics can lead to better usage of them and avoiding some of their traps.

      1 Reply Last reply
      4
      • fcarneyF fcarney

        @Kent-Dorfman Knowing memory layout can be REALLY important. The lack of that knowledge can introduce bugs. Like the static initialization order problems. It should also be noted that static/global vars are initialized by the OS before main executes. While this init may not occur on an embedded system with no OS. So it can affect portability of code.

        JonBJ Online
        JonBJ Online
        JonB
        wrote on last edited by
        #7

        @fcarney said in Static Member variable and static member function resides in ????:

        @Kent-Dorfman Knowing memory layout can be REALLY important. The lack of that knowledge can introduce bugs. Like the static initialization order problems.

        Since this question is still going on: How does knowing anything about memory layout address anything about the static initialization order problem you linked to?

        fcarneyF 1 Reply Last reply
        0
        • JonBJ JonB

          @fcarney said in Static Member variable and static member function resides in ????:

          @Kent-Dorfman Knowing memory layout can be REALLY important. The lack of that knowledge can introduce bugs. Like the static initialization order problems.

          Since this question is still going on: How does knowing anything about memory layout address anything about the static initialization order problem you linked to?

          fcarneyF Offline
          fcarneyF Offline
          fcarney
          wrote on last edited by
          #8

          @JonB I kinda lumped it into knowing when and where things are happening. That problem in particular may not be all that relevant. I found it interesting because I found out that the OS does initialize the global memory for the app at startup ("and is zeroed out by the OS when loading the program"). This zero init does not happen on systems without an OS so may provide challenges for portability of code. I found this out when researching why I was having init problems of static/global variables that accessed the same data structure from different compilation units. This lead to a series of investigations to find out if I really did need to init some variables or not. There was a constructor that would overwrite things when it wasn't really needed. That code is legacy and needs to be reworked, but unfortunately it is production code at the moment. So yeah, not directly related, but definitely in a similar realm of knowledge in my mind. To me, at times, it has been important to have some kind of idea of memory layout when coding. Of course this is more important when doing things system wise like firmware development or microcontrollers. Desktop apps, not so much, unless memory is highly constrained for some reason. Then it might be important.

          C++ is a perfectly valid school of magic.

          jsulmJ 1 Reply Last reply
          0
          • fcarneyF fcarney

            @JonB I kinda lumped it into knowing when and where things are happening. That problem in particular may not be all that relevant. I found it interesting because I found out that the OS does initialize the global memory for the app at startup ("and is zeroed out by the OS when loading the program"). This zero init does not happen on systems without an OS so may provide challenges for portability of code. I found this out when researching why I was having init problems of static/global variables that accessed the same data structure from different compilation units. This lead to a series of investigations to find out if I really did need to init some variables or not. There was a constructor that would overwrite things when it wasn't really needed. That code is legacy and needs to be reworked, but unfortunately it is production code at the moment. So yeah, not directly related, but definitely in a similar realm of knowledge in my mind. To me, at times, it has been important to have some kind of idea of memory layout when coding. Of course this is more important when doing things system wise like firmware development or microcontrollers. Desktop apps, not so much, unless memory is highly constrained for some reason. Then it might be important.

            jsulmJ Offline
            jsulmJ Offline
            jsulm
            Lifetime Qt Champion
            wrote on last edited by
            #9

            @fcarney Just a note: you should always initialize all your variables and not trust OS/framework/whatever to do it for you :-)

            https://forum.qt.io/topic/113070/qt-code-of-conduct

            Chris KawaC 1 Reply Last reply
            0
            • jsulmJ jsulm

              @fcarney Just a note: you should always initialize all your variables and not trust OS/framework/whatever to do it for you :-)

              Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #10

              @jsulm I'd say you should usually initialize your variables. There are a lot of C style APIs out there that, for example, take a reference to a data structure and fill it out. Initializing the members beforehand is just wasteful and compiler can't always optimize redundant writes like that, especially on function boundaries. I've seen a case with code like

              Foo array_of_foos[COUNT];
              ...
              Initialize(array_of_foos);
              

              where someone innocently enough did a static analysis pass and the tool suggested

              Foo array_of_foos[COUNT] {};
              

              This started to show up badly in profiles. Generally I would avoid words like "always" and "never" in C++. "Most of the time" or "rarely" seem to fit a lot better with reality.

              1 Reply Last reply
              4
              • JonBJ Online
                JonBJ Online
                JonB
                wrote on last edited by JonB
                #11

                I'm a touch confused about one thing which is being said. (Yes, I could go look it up somewhere, but I prefer to ask here.)

                Earlier @fcarney said in Static Member variable and static member function resides in ????:

                It should also be noted that static/global vars are initialized by the OS before main executes. While this init may not occur on an embedded system with no OS. So it can affect portability of code.

                int fred[100];
                
                void func()
                {
                    static char jim[100];
                }
                

                In my day both fred & jim were guaranteed initialized to 0s (zeroes), and AFAIR that was specified in the C language. Are you saying that an OS implementation does not have to do that, so it's not a feature of the language?

                1 Reply Last reply
                0
                • fcarneyF Offline
                  fcarneyF Offline
                  fcarney
                  wrote on last edited by
                  #12

                  I am going by what cppreference says. It says the OS initializes some things. I have no idea if the OS "has" to or not. My guess it is supposed to. On an embedded system, without an OS, then there is no OS to init this memory.

                  C++ is a perfectly valid school of magic.

                  1 Reply Last reply
                  0
                  • Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by
                    #13

                    @fcarney said:

                    I am going by what cppreference says. It says the OS initializes some things. I have no idea if the OS "has" to or not. My guess it is supposed to.

                    C++ standard says those are initialized. It does not say an OS should or shouldn't do that. It has no notion of an OS. How this initialization is done is implementation defined and a conforming toolchain will do whatever is required to achieve that effect on given platform. In some cases it may be a compile time initialization stored in the executable image, for some the OS loader may take care of that at load time and for other cases (like no OS) the compiler might generate explicit code run before main() to initialize those variables. The point is that C++ standard does not define how a given effect is to be achieved, only that it is. This is intentional, as it does not impose artificial requirements on platforms and is left for toolchain implementers to do whatever is the best option for their platform.

                    fcarneyF 1 Reply Last reply
                    4
                    • kshegunovK Offline
                      kshegunovK Offline
                      kshegunov
                      Moderators
                      wrote on last edited by kshegunov
                      #14

                      These discussions are so cool! :)

                      Edit:
                      @Chris-Kawa said in Static Member variable and static member function resides in ????:

                      How this initialization is done is implementation defined

                      With major note that the standard dictates trivial initializations happen before non-trivial ones. And this is a behaviour one can rely on.

                      Read and abide by the Qt Code of Conduct

                      1 Reply Last reply
                      5
                      • Chris KawaC Chris Kawa

                        @fcarney said:

                        I am going by what cppreference says. It says the OS initializes some things. I have no idea if the OS "has" to or not. My guess it is supposed to.

                        C++ standard says those are initialized. It does not say an OS should or shouldn't do that. It has no notion of an OS. How this initialization is done is implementation defined and a conforming toolchain will do whatever is required to achieve that effect on given platform. In some cases it may be a compile time initialization stored in the executable image, for some the OS loader may take care of that at load time and for other cases (like no OS) the compiler might generate explicit code run before main() to initialize those variables. The point is that C++ standard does not define how a given effect is to be achieved, only that it is. This is intentional, as it does not impose artificial requirements on platforms and is left for toolchain implementers to do whatever is the best option for their platform.

                        fcarneyF Offline
                        fcarneyF Offline
                        fcarney
                        wrote on last edited by
                        #15

                        @Chris-Kawa said in Static Member variable and static member function resides in ????:

                        left for toolchain implementers to do whatever is the best option for their platform

                        So I did test this on an embedded platform. It was an Arduino IDE based platform (Teensy 4 in this case). It does indeed init arrays declared in the global/static region of the code. For testing I created an array of structs. Looping through I was able to confirm that everything was zeroed out. Thanks for the clarification.

                        C++ is a perfectly valid school of magic.

                        1 Reply Last reply
                        1
                        • Kent-DorfmanK Online
                          Kent-DorfmanK Online
                          Kent-Dorfman
                          wrote on last edited by
                          #16

                          @fcarney said in Static Member variable and static member function resides in ????:

                          For testing I created an array of structs. Looping through I was able to confirm that everything was zeroed out. Thanks for the clarification.

                          That's not a valid test. initailize with a unique bit pattern. Power off, then restart the board and verify the bit patterns after reinitialization. Also read the standard regarding object/variable initialization. The rules are here:
                          https://en.cppreference.com/w/cpp/language/default_initialization

                          What is not defined is the order of static initialization. Thats why it is important to initialize static members as part of the main() startup: "construct on first use".

                          Chris KawaC 1 Reply Last reply
                          0
                          • Kent-DorfmanK Kent-Dorfman

                            @fcarney said in Static Member variable and static member function resides in ????:

                            For testing I created an array of structs. Looping through I was able to confirm that everything was zeroed out. Thanks for the clarification.

                            That's not a valid test. initailize with a unique bit pattern. Power off, then restart the board and verify the bit patterns after reinitialization. Also read the standard regarding object/variable initialization. The rules are here:
                            https://en.cppreference.com/w/cpp/language/default_initialization

                            What is not defined is the order of static initialization. Thats why it is important to initialize static members as part of the main() startup: "construct on first use".

                            Chris KawaC Offline
                            Chris KawaC Offline
                            Chris Kawa
                            Lifetime Qt Champion
                            wrote on last edited by Chris Kawa
                            #17

                            @Kent-Dorfman said in Static Member variable and static member function resides in ????:

                            Thats why it is important to initialize static members as part of the main() startup: "construct on first use".

                            No, that's not how it works. Global static variables are initialized before main(). They might have side effects which need to be visible before the variable itself is used. Heck, there might even not be any main() in your program. For example MFC framework has just a static global variable that runs event loop from its constructor. There usually is no main() in such app and yet it still runs.

                            JonBJ 1 Reply Last reply
                            3
                            • Chris KawaC Chris Kawa

                              @Kent-Dorfman said in Static Member variable and static member function resides in ????:

                              Thats why it is important to initialize static members as part of the main() startup: "construct on first use".

                              No, that's not how it works. Global static variables are initialized before main(). They might have side effects which need to be visible before the variable itself is used. Heck, there might even not be any main() in your program. For example MFC framework has just a static global variable that runs event loop from its constructor. There usually is no main() in such app and yet it still runs.

                              JonBJ Online
                              JonBJ Online
                              JonB
                              wrote on last edited by JonB
                              #18

                              Further to @Chris-Kawa's (correct) observation above about "Global static variables".

                              Turning to non-global scope static variables. A few months we had an interesting discussion in this forum about when these get initialized, but I don't have the reference to the thread. We were talking either about statics declared in a function, or in a class, or both, I don't recall.

                              We found these are indeed only initialized on "first use" of the function/class/whatever. We looked at the code generated to accomplish this. It turns out that the compiler generated a "hidden guard variable/memory location" for these. Effectively like a boolean initialized to 0/false to say "not yet called for initialization". On being called/created, the code tests this variable and does the initialization once at this instant if the boolean is still false. Then it sets the boolean to true, so that initialization will not occur again.

                              This allows e.g. a static initialization somewhere to reference, say, another class/object which itself is not ready to be called at start up time; it will not evaluate the reference until the calling code is actually first executed, thereby allowing the referenced object to have been initialized itself.

                              I at least found the "hidden guard" code implementation interesting :)

                              1 Reply Last reply
                              2
                              • Chris KawaC Offline
                                Chris KawaC Offline
                                Chris Kawa
                                Lifetime Qt Champion
                                wrote on last edited by Chris Kawa
                                #19

                                Yeah, function local statics are scoped, so they behave a little different. This case of static init was further complicated in C++11. Before that C++ standard had no notion of threads, so initialization of static variable in a function called simultaneously from different threads was undefined - it could be initialized once, twice, at all, partially or crash your app entirely. In C++11 this is guaranteed to be initialized exactly once. It's not specified from which thread that init occurs, only that the observed behavior is that on first use in any thread the variable is fully initialized. This got nicknamed as "magic statics". It's important to note that because of the synchronization needed function statics initialization in C++11 became kinda costly operation, so it's something to keep in mind. This also lead to a new storage specifier - thread_local.

                                kshegunovK 1 Reply Last reply
                                2
                                • Chris KawaC Chris Kawa

                                  Yeah, function local statics are scoped, so they behave a little different. This case of static init was further complicated in C++11. Before that C++ standard had no notion of threads, so initialization of static variable in a function called simultaneously from different threads was undefined - it could be initialized once, twice, at all, partially or crash your app entirely. In C++11 this is guaranteed to be initialized exactly once. It's not specified from which thread that init occurs, only that the observed behavior is that on first use in any thread the variable is fully initialized. This got nicknamed as "magic statics". It's important to note that because of the synchronization needed function statics initialization in C++11 became kinda costly operation, so it's something to keep in mind. This also lead to a new storage specifier - thread_local.

                                  kshegunovK Offline
                                  kshegunovK Offline
                                  kshegunov
                                  Moderators
                                  wrote on last edited by
                                  #20

                                  @Chris-Kawa said in Static Member variable and static member function resides in ????:

                                  It's important to note that because of the synchronization needed function statics initialization in C++11 became kinda costly operation, so it's something to keep in mind.

                                  Sort of, but on the bright side function static initialization happens on first use only (threads notwithstanding), so if you never call the method that inits it, it is never initialized (which is not true for class's statics that are the same as globals).

                                  Read and abide by the Qt Code of Conduct

                                  1 Reply Last reply
                                  3
                                  • Kent-DorfmanK Online
                                    Kent-DorfmanK Online
                                    Kent-Dorfman
                                    wrote on last edited by
                                    #21

                                    @Chris-Kawa said in Static Member variable and static member function resides in ????:

                                    No, that's not how it works. Global static variables are initialized before main(). They might have side effects which need to be visible before the variable itself is used. Heck, there might even not be any main() in your program. For example MFC framework has just a static global variable that runs event loop from its constructor. There usually is no main() in such app and yet it still runs.

                                    Referring to a 25 year old framework in a discussion of modern C++ best practices really doesn't help your case though, and even humble MFC had a main(), they just didn't call it that. I think it was _tmain() or wmain().
                                    See https://stackoverflow.com/questions/895827/what-is-the-difference-between-tmain-and-main-in-c

                                    The best practice in the regulated field I work in is to use the "construct on first use" paradigm. Global (static) objects are bad when they have interdependence upon each other. that's why it is often better to use global static pointers to those object and construct them in a well-defined order in main().

                                    I suspect we'll continue to agree to disagree. LOL

                                    Chris KawaC 1 Reply Last reply
                                    1
                                    • Kent-DorfmanK Kent-Dorfman

                                      @Chris-Kawa said in Static Member variable and static member function resides in ????:

                                      No, that's not how it works. Global static variables are initialized before main(). They might have side effects which need to be visible before the variable itself is used. Heck, there might even not be any main() in your program. For example MFC framework has just a static global variable that runs event loop from its constructor. There usually is no main() in such app and yet it still runs.

                                      Referring to a 25 year old framework in a discussion of modern C++ best practices really doesn't help your case though, and even humble MFC had a main(), they just didn't call it that. I think it was _tmain() or wmain().
                                      See https://stackoverflow.com/questions/895827/what-is-the-difference-between-tmain-and-main-in-c

                                      The best practice in the regulated field I work in is to use the "construct on first use" paradigm. Global (static) objects are bad when they have interdependence upon each other. that's why it is often better to use global static pointers to those object and construct them in a well-defined order in main().

                                      I suspect we'll continue to agree to disagree. LOL

                                      Chris KawaC Offline
                                      Chris KawaC Offline
                                      Chris Kawa
                                      Lifetime Qt Champion
                                      wrote on last edited by Chris Kawa
                                      #22

                                      Referring to a 25 year old framework in a discussion of modern C++ best practices really doesn't help your case though

                                      Why? Things haven't changed that much really. Some new stuff came along but the old is very much still there. There's still a lot of software using MFC today. I'm not saying you should use it in new projects or anything like that, but it's still there, still works and the rules of how it works didn't change, so I think it's a perfectly valid point in this discussion. I'm not talking about some obscure tech that fell out of use. It's (sadly) very much alive.

                                      and even humble MFC had a main(), they just didn't call it that. I think it was _tmain() or wmain().

                                      Right, well, it's, again, a little bit more complicated. Yes, that framework provides a _tWinMain that called AfxWinMain and that's one way to make an MFC app, but you can also skip that and start the event pump another way. Anyways, I don't want to get into MFC discussion, that wasn't the point :P The point was you don't need a main() or any other function to initialize global statics and run some code in their constructors. Another example is global statics in dynamically loaded libraries. I hope this one is less controversial :)

                                      The best practice in the regulated field I work in is to use the "construct on first use" paradigm.

                                      I think we have a misunderstanding coming from that name, but the thing it names is a perfectly valid strategy, I agree.

                                      Global (static) objects are bad when they have interdependence upon each other.

                                      I absolutely agree. If I seemed to advocate for using static globals let me be very clear - I'm not. They have their uses, sure, but also the order of initialization problem you mentioned, so that's something to take into account in your app design. If it matters - don't do it, if it doesn't - go ahead. I was merely trying to convey how they work on a technical level.

                                      that's why it is often better to use global static pointers to those object and construct them in a well-defined order in main().

                                      See, I think this is the point of confusion we had. If you use global pointers then those pointers get initialized (zeroed) in the way I was taking about. The pointers, not the objects that they later point to and you can obviously assign to them in main() or wherever else in a controlled order that you like. The pointers themselves though are originally initialized for you in an unspecified order. It doesn't really matter in that scenario of course as you overwrite them later in a way you see fit. The gist of it is that the pointers are the global static objects we're talking about here, not the things they later point to.

                                      I suspect we'll continue to agree to disagree. LOL

                                      I think we actually agree. We just misunderstood each other on some technicalities ;)

                                      1 Reply Last reply
                                      3

                                      • Login

                                      • Login or register to search.
                                      • First post
                                        Last post
                                      0
                                      • Categories
                                      • Recent
                                      • Tags
                                      • Popular
                                      • Users
                                      • Groups
                                      • Search
                                      • Get Qt Extensions
                                      • Unsolved