Static constructors/destructors in C++

7,189 views
Skip to first unread message

Mariusz Moczala

unread,
Jul 22, 2016, 11:52:17 AM7/22/16
to ISO C++ Standard - Future Proposals

For over years I heard interview questions like: “does C++ have a static constructor” or “what static constructor do”. Of course there is no such type of constructors in C++. However it would be extremely useful…

 

My proposition is to provide a static constructor and destructor in C++. The static constructor will be executed once before main() function and static destructor just after it. So it works in the same manner as for a global object with one difference: there is no associated object. Static ctor/dtor is called once, even if object was never created. It generally behave as usual static function. Therefore you cannot use this pointer within such ctor/dtor.

 

I see a numerous purposes for this thing. The most important are:

  • Easier class registration/deregistration
  • New mechanism for singleton implementation
  • Class code can be now executed w/o creating object and w/o external call.
  • And the best one: Including/Excluding h/cpp file into application allows enabling/disabling functionality without using preprocessor.

 

let’s consider a following example:

 

class MyPlugin : public Plugin {

  private:

    Plugin &getPluginInstance() {

      static MyPlugin myPlugin;

      return myPlugin;

    }

  public:

    static MyPlugin() {

      Plugins::registerPlugin(getPluginInstance());

    }

    static ~MyPlugin() {

      Plugins::unregisterPlugin(getPluginInstance());

    }

};


Here are the rules:

  • Static constructors of different classes are executed one by one in the same order as corresponding classes were defined.
  • Static constructors are always executed before software entry point (the main() function) and always before constructors of all global objects.
  • Static destructors are executed one by one in reverse order to the order of corresponding classes definition.
  • Static destructors are always executed after software entry point and always after constructors of all global objects.
  • If both base and derived class have a static constructor, first is called a static constructor of base class
  • If both base and derived class have a static destructor, first is called a static destructor of derived class
  • static constructor and destructor have no parameters
  • static constructor and destructor behaves as usual static function
  • this pointer cannot be used within static constructor nor destructor
  • I suggest to disallow manual call of static ctor/dtor. It should be autonomous mechanism for specific purposes only. Callable functionality should be always provided as named functions or overloaded operators according to its purpose.

szollos...@gmail.com

unread,
Jul 22, 2016, 12:04:29 PM7/22/16
to ISO C++ Standard - Future Proposals
Hi,

How is it different from a static bool member variable that's initialized by the return value of your constructor? This additionally helps you by allowing return value: this is needed as you couldn't throw from a static constructor to signal errors. If you wanted a destructor as well, then have a static struct StaticMyPlugin { StaticMyPlugin() { ... } ~StaticMyPlugin() { ... } } staticMyPlugin; This is almost the syntax you wanted.

Regards,
-lorro

Thiago Macieira

unread,
Jul 22, 2016, 12:05:34 PM7/22/16
to std-pr...@isocpp.org
On sexta-feira, 22 de julho de 2016 08:52:16 PDT Mariusz Moczala wrote:
> For over years I heard interview questions like: “does C++ have a static
> constructor” or “what static constructor do”. Of course there is no such
> type of constructors in C++. However it would be extremely useful…

What you described below does exist and has been part of the language since
C++98, except that it requires an object. I don't see the committee adding
another syntax to do the same thing that is already possible.

> I see a numerous purposes for this thing. The most important are:
>
>
> - Easier class registration/deregistration
> - New mechanism for singleton implementation
> - Class code can be now executed w/o creating object and w/o external
> call.

Please explain how this is superior to the existing alternative.

> - And the best one: Including/Excluding h/cpp file into application
> allows enabling/disabling functionality without using preprocessor.

And please explain how this would happen. I don't see it.

> Here are the rules:
>
> - Static constructors of different classes are executed one by one in
> the same order as corresponding classes were defined.

Classes are not defined in any order. This point must either be completely
gone, saying that the registration is done in any arbitrary order, or you must
provide an explanation of how the compiler and linker in a project with 1000
translation units would know what the order is.

And please think of the dynamic linker when there are 50 libraries loaded.

And then consider what happens when you load plugins simultaneously from two
different threads.

> - Static constructors are always executed before software entry point
> (the main() function) and always before constructors of all global
> objects.
> - Static destructors are executed one by one in reverse order to the
> order of corresponding classes definition.
> - Static destructors are always executed after software entry point and
> always after constructors of all global objects.

Considering the lack of ordering of the point above, I don't see how this
would work. Is running something before the other constructors the most
important feature?

> - If both base and derived class have a static constructor, first is
> called a static constructor of base class
> - If both base and derived class have a static destructor, first is
> called a static destructor of derived class

Same ordering problem as before, now more difficult: this requires that the
linker figure out the inheritance graph.

> - static constructor and destructor have no parameters
> - static constructor and destructor behaves as usual static function
> - this pointer cannot be used within static constructor nor destructor
> - I suggest to disallow manual call of static ctor/dtor. It should be
> autonomous mechanism for specific purposes only. Callable functionality
> should be always provided as named functions or overloaded operators
> according to its purpose.


--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

Patrice Roy

unread,
Jul 22, 2016, 12:08:03 PM7/22/16
to std-pr...@isocpp.org
What do you mean by «return value of your constructor»?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/fae9f871-7738-41c3-b058-9c7ae6efd55d%40isocpp.org.

Nicol Bolas

unread,
Jul 22, 2016, 12:08:17 PM7/22/16
to ISO C++ Standard - Future Proposals
On Friday, July 22, 2016 at 11:52:17 AM UTC-4, Mariusz Moczala wrote:

For over years I heard interview questions like: “does C++ have a static constructor” or “what static constructor do”. Of course there is no such type of constructors in C++. However it would be extremely useful…

 

My proposition is to provide a static constructor and destructor in C++. The static constructor will be executed once before main() function and static destructor just after it. So it works in the same manner as for a global object with one difference: there is no associated object. Static ctor/dtor is called once, even if object was never created. It generally behave as usual static function. Therefore you cannot use this pointer within such ctor/dtor.

 

I see a numerous purposes for this thing. The most important are:

  • Easier class registration/deregistration
  • New mechanism for singleton implementation
1) What's wrong with the current singleton implementations?

2) Why should we add a feature for something that's widely considered to be a bad idea in the first place?
  • Class code can be now executed w/o creating object and w/o external call.
Why is it important that we have a constructor/destructor pair without an object? Are we running out of objects?
  • And the best one: Including/Excluding h/cpp file into application allows enabling/disabling functionality without using preprocessor.
In what way? Or more to the point, in what way would this do what you want that couldn't be done with an actual object?

let’s consider a following example:

 

class MyPlugin : public Plugin {

  private:

    Plugin &getPluginInstance() {

      static MyPlugin myPlugin;

      return myPlugin;

    }

  public:

    static MyPlugin() {

      Plugins::registerPlugin(getPluginInstance());

    }

    static ~MyPlugin() {

      Plugins::unregisterPlugin(getPluginInstance());

    }

};


Here are the rules:

  • Static constructors of different classes are executed one by one in the same order as corresponding classes were defined.
That's great. What order is that, exactly?

If definitions were actually ordered, we wouldn't have a problem with global/static object initialization ordering.
  • Static constructors are always executed before software entry point (the main() function) and always before constructors of all global objects.
  • Static destructors are executed one by one in reverse order to the order of corresponding classes definition.
  • Static destructors are always executed after software entry point and always after constructors of all global objects.
  • If both base and derived class have a static constructor, first is called a static constructor of base class
  • If both base and derived class have a static destructor, first is called a static destructor of derived class
  • static constructor and destructor have no parameters
  • static constructor and destructor behaves as usual static function
  • this pointer cannot be used within static constructor nor destructor
Your example constructor used `this` just fine. How else could it call the non-static `getPluginInstance` function? Or did you mean for that function to be static too?

Mariusz Moczala

unread,
Jul 22, 2016, 1:11:02 PM7/22/16
to ISO C++ Standard - Future Proposals
Thank you very much for all comments. Please have a look at the simplified code once again:

class MyPlugin : public Plugin {
  public:
    static MyPlugin() {
      static MyPlugin myPlugin;
      Plugins::registerPlugin(myPlugin);
    }
    ~MyPlugin() {
      Plugins::unregisterPlugin(*this);
    }
};

This is a complete, executable code. Previously I have forgotten static keyword for getPluginInstance function. Thank you for pointing this out!

Let’s consider the plug-in registration. Currently in C++ to execute class code, you need to at least create an object to execute default constructor’s code. You can also call a static function. However to register a new plug-in, programmer have to write some code.

With static constructors you can just add a cpp / obj / lib file into your project. Or just include a header file with above class in any source file. The static constructor of MyPlugin class will create a static object, so you do not need to do this manually in a cpp file. The static constructor also calls Plugins::registerPlugin on the object, so it is also automatically registered. Just by a including header file.

After reading your comments I found that there is actually no need for static destructor. As you can create a static object in static constructor, then regular destructor can perform a deregistration. According to this, there is no longer need to consider the execution order.

Briefly, the linker should now operate this way:
  • Call static constructors form all translation units and libs
  • Call constructors for global variables (as usual)
  • Call main() function (as usual)
  • Call destructors for global variables (as usual)
Please correct me if I am missing something here: If lib file have a static constructor providing plugin registration, it will be automatically executed and there is no longer need to provide a header file associated with the lib to use it in a project.

Thiago Macieira

unread,
Jul 22, 2016, 1:43:43 PM7/22/16
to std-pr...@isocpp.org
On sexta-feira, 22 de julho de 2016 10:11:02 PDT Mariusz Moczala wrote:
> Let’s consider the plug-in registration. Currently in C++ to execute class
> code, you need to at least create an object to execute default
> constructor’s code. You can also call a static function. However to
> register a new plug-in, programmer have to write some code.

Yes, it's an issue we have with plugin registration in Qt.

> With static constructors you can just add a cpp / obj / lib file into your
> project.

That's not how the linkers work. If the plugin is in a static library (.a or
.lib file), you have to somehow *use* the file before the linker will consider
it. You need to call a function or use a variable defined in the specific .o or
.obj file that the contains the registration code.

The most obvious solution is to call the registration function.

But this highlights the other problem of your proposal: your static
constructors and destructors are run despite never being ODR-used. They simply
exist and therefore should be called, in an order that the compiler doesn't
know but should.

> Or just include a header file with above class in any source file.
> The static constructor of MyPlugin class will create a static object, so
> you do not need to do this manually in a cpp file. The static constructor
> also calls Plugins::registerPlugin on the object, so it is also
> automatically registered. Just by a including header file.

If you're going to include a header, then you could continue to use the
existing functionality. The only difference from what you're proposing to what
exists is that your header could be included from multiple translation units
without causing duplicate definitions.

> After reading your comments I found that there is actually no need for
> static destructor. As you can create a static object in static constructor,
> then regular destructor can perform a deregistration. According to this,
> there is no longer need to consider the execution order.
>
> Briefly, the linker should now operate this way:
>
> - Call static constructors form all translation units and libs

What order?

> - Call constructors for global variables (as usual)
> - Call main() function (as usual)
> - Call destructors for global variables (as usual)
>
> Please correct me if I am missing something here: If lib file have a static
> constructor providing plugin registration, it will be automatically
> executed and there is no longer need to provide a header file associated
> with the lib to use it in a project.

Except for the ODR-use.

Nicol Bolas

unread,
Jul 22, 2016, 1:45:29 PM7/22/16
to ISO C++ Standard - Future Proposals
On Friday, July 22, 2016 at 1:11:02 PM UTC-4, Mariusz Moczala wrote:
Thank you very much for all comments. Please have a look at the simplified code once again:

class MyPlugin : public Plugin {
  public:
    static MyPlugin() {
      static MyPlugin myPlugin;
      Plugins::registerPlugin(myPlugin);
    }
    ~MyPlugin() {
      Plugins::unregisterPlugin(*this);
    }
};

This is a complete, executable code. Previously I have forgotten static keyword for getPluginInstance function. Thank you for pointing this out!

Let’s consider the plug-in registration. Currently in C++ to execute class code, you need to at least create an object to execute default constructor’s code. You can also call a static function. However to register a new plug-in, programmer have to write some code.

So do you. You had to write the static constructor in question. Something which could have been done like this:

class MyPlugin : public Plugin {
 
public:

   
~MyPlugin() {
     
Plugins::unregisterPlugin(*this);
   
}

 
private:
   
struct Reg
   
{
     
Reg() {

       
static MyPlugin myPlugin;
       
Plugins::registerPlugin(myPlugin);
     
}

   
};

   
static inline Reg register;
};

So why do we need a way to do something that we already know how to do?
 
With static constructors you can just add a cpp / obj / lib file into your project. Or just include a header file with above class in any source file.
 
The static constructor of MyPlugin class will create a static object, so you do not need to do this manually in a cpp file. The static constructor also calls Plugins::registerPlugin on the object, so it is also automatically registered. Just by a including header file.

After reading your comments I found that there is actually no need for static destructor. As you can create a static object in static constructor, then regular destructor can perform a deregistration. According to this, there is no longer need to consider the execution order.

Briefly, the linker should now operate this way:
  • Call static constructors form all translation units and libs
  • Call constructors for global variables (as usual)
  • Call main() function (as usual)
  • Call destructors for global variables (as usual)
Please correct me if I am missing something here: If lib file have a static constructor providing plugin registration, it will be automatically executed and there is no longer need to provide a header file associated with the lib to use it in a project.

Allow me to restate what you just said:

Please correct me if I am missing something here: If lib file have a static object providing plugin registration, it will be automatically executed and there is no longer need to provide a header file associated with the lib to use it in a project.

So why do we need a static constructor if a static object will do the exact same thing? You're not giving us something new; you're only creating a slightly more convenient way to do it.

Sergey Vidyuk

unread,
Jul 23, 2016, 2:00:56 AM7/23/16
to ISO C++ Standard - Future Proposals
So why do we need a static constructor if a static object will do the exact same thing? You're not giving us something new; you're only creating a slightly more convenient way to do it.

Static object with nontrivial constructor in a library you rae linking with:
 * might be some dead code you don't need (but might be needed by other code base which uses this static object). In this case constructor call might be freely elliminated by LTO
 * or can be a hack in order to have some code which do some lmportant library initializations and must never be eliminated by LTO

Static class constructor is not "more convenient way to have class level or library level initialization in C++". Is completely new feature which provide you the only way to have such initialization. Current approach is attempt to use some side-effect of another feature which is not reliable in real world compilers without disabling important optimizations (there are tricks like get address of a dummy static registrator variable from some function which will be called. Necessity to have such strange code is the best motivation example why static constructors is good feature to add to C++).

This feature opens posibility to deprecate and remove in C++2023 or 2026 requirement on static object constructor invocation if this static object is mever used or used from unreachable code only (I'm unsure if such term like "reachable code" is defined in the standard so might be required to define it). I do want to rely on dead static elliminaion in case of static linkage. The company I'm working in now bought Qt license for 2 reasons: 1) QML compiler 2) Static linking with Qt gives smaller APK on android. Binary size reduce might be even more efficient with some help from the new laguage standards.

Sergey Vidyuk

Mariusz Moczala

unread,
Jul 23, 2016, 5:20:49 AM7/23/16
to ISO C++ Standard - Future Proposals
Thank you very much for all constructive comments!



I would like to propose one extension to the static class constructor. It should also allow to initialize static class variables through member initializer list, similarly to non-static class constructor for non-static members:

class MyPlugin
{
    public:

        static int abc;
        static MyPlugin() : abc(4) { }
};



So why do we need a static constructor if a static object will do the exact same thing? You're not giving us something new; you're only creating a slightly more convenient way to do it.
To have a static object you have to create it first, somewhere outside the class. Static class constructor allows you to do this within a class body. Please consider following example with a macro definition like this:

#define REGISTER_PLUGIN(Plugin) class __Init##Plugin##_t { public: __Init##Plugin##_t() { static Plugin plugin; Plugins::registerPlugin(plugin); } } __init##Plugin

The static class constructor allows you to avoid preprocessor usage and to do this with "a slightly more convenient way". :)



Regarding ODR: I need to think it out carefully for different cases. I'll come  with this later.



Thanks,
Mariusz

Robert Bielik

unread,
Jul 23, 2016, 6:09:52 AM7/23/16
to std-pr...@isocpp.org
+1 for this as I've on many occasions missed the possibility to have non-header exposed static initialization of polymorphic objects in libraries.

Regards
/R

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Jul 23, 2016, 11:39:38 AM7/23/16
to ISO C++ Standard - Future Proposals
On Saturday, July 23, 2016 at 2:00:56 AM UTC-4, Sergey Vidyuk wrote:
So why do we need a static constructor if a static object will do the exact same thing? You're not giving us something new; you're only creating a slightly more convenient way to do it.

Static object with nontrivial constructor in a library you rae linking with:
 * might be some dead code you don't need (but might be needed by other code base which uses this static object). In this case constructor call might be freely elliminated by LTO 
 * or can be a hack in order to have some code which do some lmportant library initializations and must never be eliminated by LTO

Inline variables seem to solve this problem. From the PDF, I gather that the intent is that the constructor/destructor for inline variables are always called, whether they are ODR used or not. And therefore, you can rely on their side-effects.

Static class constructor is not "more convenient way to have class level or library level initialization in C++". Is completely new feature which provide you the only way to have such initialization. Current approach is attempt to use some side-effect of another feature which is not reliable in real world compilers without disabling important optimizations (there are tricks like get address of a dummy static registrator variable from some function which will be called. Necessity to have such strange code is the best motivation example why static constructors is good feature to add to C++).

If the standard says that the constructors of static objects must be called, then they must be called. And "real world compilers" that stop doing that are broken.

Nicol Bolas

unread,
Jul 23, 2016, 11:41:57 AM7/23/16
to ISO C++ Standard - Future Proposals
On Saturday, July 23, 2016 at 5:20:49 AM UTC-4, Mariusz Moczala wrote:
So why do we need a static constructor if a static object will do the exact same thing? You're not giving us something new; you're only creating a slightly more convenient way to do it.
To have a static object you have to create it first, somewhere outside the class.

Inline variables are a thing now. Or will be in C++17. So no, you don't; you can put that in a header just fine.

Thiago Macieira

unread,
Jul 23, 2016, 12:54:20 PM7/23/16
to std-pr...@isocpp.org
On sábado, 23 de julho de 2016 08:39:37 PDT Nicol Bolas wrote:
> Inline variables
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4424.pdf>seem to
> solve this problem. From the PDF, I gather that the intent is that the
> constructor/destructor for inline variables are always called, whether they
> are ODR used or not. And therefore, you can rely on their side-effects.

Has this been implemented as a proof of concept in any compler?

I don't remember this as a consequence of inline variables when we were
discussing them. They were either constexpr or evaluated on use, as opposed to
intialised some time in the past.

Nicol Bolas

unread,
Jul 23, 2016, 5:07:26 PM7/23/16
to ISO C++ Standard - Future Proposals


On Saturday, July 23, 2016 at 12:54:20 PM UTC-4, Thiago Macieira wrote:
On sábado, 23 de julho de 2016 08:39:37 PDT Nicol Bolas wrote:
> Inline variables
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4424.pdf>seem to
> solve this problem. From the PDF, I gather that the intent is that the
> constructor/destructor for inline variables are always called, whether they
> are ODR used or not. And therefore, you can rely on their side-effects.

Has this been implemented as a proof of concept in any compler?

I don't remember this as a consequence of inline variables when we were
discussing them. They were either constexpr or evaluated on use, as opposed to
intialised some time in the past.

I don't know enough about that part of the standard to interpret what the wording means in this regard. But the motivation section seems like it's calling out the need to ODR-use such variables in order to be able to rely on their constructor side-effects as one of the reasons for the feature. So I assume that the wording introduces that ability.

But I could be wrong.
Message has been deleted

Mariusz Moczala

unread,
Jul 26, 2016, 10:50:34 AM7/26/16
to ISO C++ Standard - Future Proposals
Hello once again,

Please tell me what do you think about the following example:

#include <cstdio>
#include <string>

class LogFile
{
    private:

        FILE *file;


    public:

        LogFile() :
            file(NULL)
        {
        }

        ~LogFile()
        {
            close();
        }

        void append(const char *fileName)
        {
            close();
            file = fopen(fileName, "a+t");
        }

        void close()
        {
            if(file) {
                fclose(file);
                file = NULL;
            }
        }

        bool isOpened() const
        {
            return file != NULL;
        }

        void write(const char *message)
        {
            fprintf(file, "%s\n", message);
        }
};

class Log
{
    private:

        static LogFile logFile;


    public:

        static Log()
        {
            logFile.append("log.txt");
            if(!logFile.isOpened())
                fprintf(stderr, "ERROR: Failed to create 'log.txt' file.\n");
        }


    private:

        std::string str;


    public:

        ~Log()
        {
            logFile.write(str.c_str());
        }

        void write(const char *text)
        {
            if(str.length())
                str += "    ";
            str += text;
            str += '\n';
        }
};

int main()
{
    Log logAlpha, logNum;
    logAlpha.write("A message");
    logNum.write("1 message");
    logAlpha.write("B message");
    logNum.write("2 message");
    logAlpha.write("C message");
    logNum.write("3 message");

    return 0;
}

OUTPUT:

1 message
    2 message
    3 message

A message
    B message
    C message

Regarding the code marked in blue:
  • The static logFile variable is defined because a static class constructor is defined. The static variable can be also initialized through initializer list
  • The static class constructor is executed once, so you can perform actions like filie open
  • The static logFile variable will be destroyed on application termination as usual static variable
  • Is this a kind of a singleton or not?

Many thanks,
Mariusz

Patrice Roy

unread,
Jul 26, 2016, 11:07:46 AM7/26/16
to std-pr...@isocpp.org
Given that we can get the same effect with existing language features such as :

class Log {
   struct LogFileHandler {
      LogFile file;
      LogFileHandler() {
         file.append("log.txt");
         if (!file.is_open())

            fprintf(stderr, "ERROR: Failed to create 'log.txt' file.\n");
      }
   };
   static LogFileHandler handler;

   std::string str;
public:
   ~Log() {
      handler.file.write(str.c_str());
   }
   void write(const char *text) {
      if (!str.empty())

         str += "    ";
      str += text;
      str += '\n';
   }
};

// ...
Log::LogFileHandler Log::handler;

... I fail to see the gains from the additional syntax, at least in C++ (other languages like C# or Java gain from this, but they instantiate objects quite differently). What does it bring that we cannot already do with minimal effort?


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Sergey Vidyuk

unread,
Jul 26, 2016, 11:21:14 AM7/26/16
to ISO C++ Standard - Future Proposals
вторник, 26 июля 2016 г., 21:50:34 UTC+7 пользователь Mariusz Moczala написал:

Log example is bad because you do need static variable and want it to be initialized before main this scenario is covered by constructor of your static variable quite well. Plugin registration example is great because nobody need any variable. The only thing required is some code to be executed automatically but dummy unused variable is needed only because of no way to execute it in a proper (non-hackish) way.

Sergey Vidyuk

Mariusz Moczala

unread,
Jul 26, 2016, 11:21:39 AM7/26/16
to ISO C++ Standard - Future Proposals
... I fail to see the gains from the additional syntax, at least in C++ (other languages like C# or Java gain from this, but they instantiate objects quite differently). What does it bring that we cannot already do with minimal effort?

Of course you can do it this way, but as I said before, you need to define somewhere in cpp file this: Log::LogFileHandler Log::handler. Therefore it will not work for header-only libraries.

Sergey Vidyuk

unread,
Jul 26, 2016, 11:26:07 AM7/26/16
to ISO C++ Standard - Future Proposals

... I fail to see the gains from the additional syntax, at least in C++ (other languages like C# or Java gain from this, but they instantiate objects quite differently). What does it bring that we cannot already do with minimal effort?


It allows to tweek language in the future to make existing Link Time Optimisations which elliminate unused static variables and their constructors standard complying. Those kind of optimisations are extremely usfull to shrink final executable and improve startup time when using huge frameworks.

Sergey Vidyuk

Sergey Vidyuk

unread,
Jul 26, 2016, 11:28:55 AM7/26/16
to ISO C++ Standard - Future Proposals
вторник, 26 июля 2016 г., 22:21:39 UTC+7 пользователь Mariusz Moczala написал:
... I fail to see the gains from the additional syntax, at least in C++ (other languages like C# or Java gain from this, but they instantiate objects quite differently). What does it bring that we cannot already do with minimal effort?

Of course you can do it this way, but as I said before, you need to define somewhere in cpp file this: Log::LogFileHandler Log::handler. Therefore it will not work for header-only libraries.

inline variables are going to solve this issue. Using static class constructor initialize static variable is the same type of hack as using dummy unused variable to execute some library initialization code :)

Sergey Vidyuk

Mariusz Moczala

unread,
Jul 26, 2016, 11:37:34 AM7/26/16
to ISO C++ Standard - Future Proposals
inline variables are going to solve this issue. Using static class constructor initialize static variable is the same type of hack as using dummy unused variable to execute some library initialization code :)

Does static inline variables allow to do something like this?

static MyClass() :
  staticMember1(123, 456),
  staticMember2("example"),
  staticMember3(staticMember1, staticMember2)
{
}

Sergey Vidyuk

unread,
Jul 26, 2016, 11:45:03 AM7/26/16
to ISO C++ Standard - Future Proposals
вторник, 26 июля 2016 г., 22:37:34 UTC+7 пользователь Mariusz Moczala написал:

It's better to check proposal wording in order to get the answer. But from my personal point of view it should be done by allowing static class members to be inline variables and the main reason to add static constructors should be ability to execute some initialization code whose desired side effect is not related to any static variable initialization.

Sergey

Mariusz Moczala

unread,
Jul 28, 2016, 10:18:25 AM7/28/16
to ISO C++ Standard - Future Proposals
Hello everyone!

Thank you very much for all extremely valuable comments.
I tried to cover all in the attached proposal.

I will be very grateful if you have any further comments and suggestions.

Thanks,
Matiusz
static class constructor.htm

Thiago Macieira

unread,
Jul 28, 2016, 2:05:00 PM7/28/16
to std-pr...@isocpp.org
On quinta-feira, 28 de julho de 2016 07:18:24 PDT Mariusz Moczala wrote:
> Static class constructor is called once for each class in the same manner as
> constructors of objects defined at global scope and always before executing
> main() function. Linker must then generate list of all static class
> constructors, to be executed by program startup code.

Please explain how the list is created and advise how ABIs should deal with
this in case of shared libraries and that of static libraries.

Assume you can't modify the linker.

szollos...@gmail.com

unread,
Jul 29, 2016, 5:17:27 AM7/29/16
to ISO C++ Standard - Future Proposals
Hi,

I do see some issues / mentionable comments:
  • You declare static constructors as if they had a return type of the class type: static MyClass() { ... };, which I think is inconsistent with current C++ grammar. Note that in the position where you've put MyClass, we usually put (loosely speaking) return type. This includes the (non-static) constructor(s), which evaluate to MyClass and have no name. Possible fixes for this include static void() { ... }; and static void MyClass() { ... };, the second being a clash on a typical error that is usually reported separately by the compiler. Or you might use a single name for all types, e.g. static void constructor() { ... };.
  • However, if your constructor really returns void, how will you handle errors? Normally constructors are either exception-safe (read: we ignore some exceptions that we want to fail early for) or report error by throwing something. Having a static int constructor_error_code doesn't really help if the constructor doesn't execute fully.
  • Your document requires linker support. That goes way beyond C++: even if we standardized static constructors, if you require linkers to be changed, then it's perhaps the best to first ask linkers to allow for this. This is a dependency for compiler implementers.
  • What about DLL / .so files? It's already kind of a nightmare to have static initialization there. These would need very clear recipes to have them defect free.
  • Correct me if I'm wrong, it'll need at least a static bool per class to know it it's been initialized as two libs might have the same class. In that case, it's just a syntax sugar over static bool constructor_result = []{ ... }();
  • I suggest underlining (and explaining why is) that, unlike default constructors, they're not auto-generated if missing. Having a static bool (non-const) for each template class I instantiate would make me invest in memory modules.
  • Which brings us to... can't these be unified? As a workaround for some static init issues, we used to have something like (feel free to laugh):


class MyClass
{
   
//...

public:
   
void deps()
   
{
        DEPS
(); // somewhere in the early headers you'll have #define DEPS() []{}()
       
#undef DEPS
       
#define DEPS() MyClass::deps()
       
static bool ready = false;
       
if(!ready)
       
{
           
// actual 'static constructor' code
       
}
   
}
};

    • Terrible as it seems, it actually fixes all the ordering issues re: dependencies, inheritance, multi-init; it can be run from main() or DllMain() by a simple DEPS();, in which case it runs after static initializers. You might take this and modify to your needs when you want to specify the as-if of static ctor implementation. You might want to expose ready (or drop it if you wish) and make tha call to DEPS(); in main()-like functions automatic.
  • You're okay to allocate one byte per class for static destructors, but didn't seem okay to allocate one bit per class for static constructor? Why is that? Or is there something I'm missing?
  • Technical details:
    • do you want static constructors to be (manually) callable?
    • do you want to be able to take their address?
    • does it make sense to have static constructors with parameters (and if yes, who would fill them: OS passing argc, argv[] or base / descendant, anyone else?)
    • is there a way to inherit static ctors? (e.g. AbstractPlugin comes to mind) If yes, how do we get current (most derived) type?
    • do you need static construction to be sequential, or just base-before-descendant? allowing for, but not requiring parallel initialization might speed up start-up without putting a burden on compilers.
    • can you instantiate _other_ classes during static construction? it's possible that their static ctor is not yet run, or that you have an inter-dependency.
    • are vtables constructed by the time constructors are run?
    • can you initialize static (const) reference members and what's the syntax?
    • can you throw an object that's class is being statically constructed?

It's possible that some of these I should've found between the lines, in which case I'm sorry. It's also totally ok to state that most of these should remain UB.


Thanks,

-lorro

Mariusz Moczala

unread,
Aug 27, 2016, 1:14:55 PM8/27/16
to ISO C++ Standard - Future Proposals

Hi,


Thank you very much for all invaluable comments!

Updated draft document D0421R1 has been attached.


Please explain how the list is created and advise how ABIs should deal with this in case of shared libraries and that of static libraries. Assume you can't modify the linker.

Good hint. I have modified it in the document. Thanks. The static class constructor, is now behaving exactly the same as a default class constructor of global variable, except have no associated object. Therefore the same mechanism can be used to execute it with NULL instead of object pointer. This does not requires to modify linker.

 

You declare static constructors as if they had a return type of the class type: static MyClass() { ... };, which I think is inconsistent with current C++ grammar. Note that in the position where you've put MyClass, we usually put (loosely speaking) return type. This includes the (non-static) constructor(s), which evaluate to MyClass and have no name. Possible fixes for this include static void() { ... }; and static void MyClass() { ... };, the second being a clash on a typical error that is usually reported separately by the compiler. Or you might use a single name for all types, e.g. static void constructor() { ... };.

I see your point, but you cannot declare function with no name, so if the function returns MyClass it will be: [static] MyClass identifier(…); but in case of default/static class constructor, you have no such problem, because MyClass is always followed by parenthesis and constructors have no returned type. Then we have no ambiguity here. Did I properly understood your comment?

 

However, if your constructor really returns void, how will you handle errors? Normally constructors are either exception-safe (read: we ignore some exceptions that we want to fail early for) or report error by throwing something. Having a static int constructor_error_code doesn't really help if the constructor doesn't execute fully.

I am not sure about this. Your static int variable if declared in global scope will be initialized before static class constructor is executed. You can then use it to mark failure initially and set it to successful just before returning from constructors code. The exceptions are working as in case of default class constructor for global variables, so will have similar problems here.

 

Your document requires linker support. That goes way beyond C++: even if we standardized static constructors, if you require linkers to be changed, then it's perhaps the best to first ask linkers to allow for this. This is a dependency for compiler implementers.

I modified the document to avoid linker modification. The static class constructors uses now the same execution mechanism as for constructors of global object.

 

What about DLL / .so files? It's already kind of a nightmare to have static initialization there. These would need very clear recipes to have them defect free.

It would be very nice to have such functionality finally working in C++. Nevertheless as linker cannot be modified, I am not addressing it anymore in the document. I’ll try to issue another document to cover this problem regarding both static class constructor and global variable initialization.

 

Correct me if I'm wrong, it'll need at least a static bool per class to know it it's been initialized as two libs might have the same class. In that case, it's just a syntax sugar over static bool constructor_result = []{ ... }()

Could you please explain it a little bit more? When you would like to use this static bool with lambda? I do know it is used to execute code once, but how is this related? The lambda will not be called if object is not created unlike the static class constructor.

 

Having a static bool (non-const) for each template class I instantiate would make me invest in memory modules.

I do not think this static bool is anywhere needed as it can be determined once on program linking stage.

 

I suggest underlining (and explaining why is) that, unlike default constructors, they're not auto-generated if missing.

Good hint, I’ll cover it. Thanks. Actually we cannot say they are auto-generated if missing. The static class constructor can initialize static class members through initializer list as non-static members are initialized through class constructor. However, if you have no default constructor, members are initialized with its default constructor. We cannot achieve this static class constructor, just to be backward compatible. If you have no static class constructor, you must define the static member outside the class body as usual. When static class constructor is defined, all static members not defined on initializer list will be initialized with its default constructor, even if they are not defined outside the class body. So the backward compatibility is the reason.

 

Which brings us to... can't these be unified? As a workaround for some static init issues, we used to have something like (feel free to laugh): […] Terrible as it seems, it actually fixes all the ordering issues re: dependencies, inheritance, multi-init; it can be run from main() or DllMain() by a simple DEPS();, in which case it runs after static initializer. You might take this and modify to your needs when you want to specify the as-if of static ctor implementation. You might want to expose ready (or drop it if you wish) and make tha call to DEPS(); in main()-like functions automatic.

Interesting. Assuming void deps() is also static. In your code you have a chain of execution, but each class depend (indirectly) on the other. Moreover DEPS is in a single translation unit only. Additionally, the more calls you have, the more stack you use. IMHO it is better/safer to build a list (array) of pointers to functions and then execute it one by one. However definitely the best way qould be tu use the static class constructor, which provides more OOP way to do this.

 

You're okay to allocate one byte per class for static destructors, but didn't seem okay to allocate one bit per class for static constructor? Why is that? Or is there something I'm missing?

Where I stated that? No additional allocations are needed. In the above example with MyPlugin, static object was used to simplify the example. However, of course depending on compiler configuration, empty class can have a zero-length.

 

do you want static constructors to be (manually) callable?

No, this feature is not available. It was already covered in document.

 

do you want to be able to take their address?

No, there is no way to do this.

 

does it make sense to have static constructors with parameters (and if yes, who would fill them: OS passing argc, argv[] or base / descendant, anyone else?)

No, you cannot pass parameters to the static class constructor. It was already covered in document.

 

is there a way to inherit static ctors? (e.g. AbstractPlugin comes to mind) If yes, how do we get current (most derived) type?

Yes. Thank you for pointing that as I forgotten to cover it in the document. Static class constructors are executed/inherited in the same manner as default constructors.

 

do you need static construction to be sequential, or just base-before-descendant? allowing for, but not requiring parallel initialization might speed up start-up without putting a burden on compilers.

Sequential approach seems to be the most appropriate and as above mentioned, the static class constructor of base class will be executed first, then are initialized static members defined (and not defined)  through the initializer list. Finally the code of static class constructor is executed.

 

can you instantiate _other_ classes during static construction? it's possible that their static ctor is not yet run, or that you have an inter-dependency.

You can instantiate classes and their static class constructors will be executed before, same as global variables are initialized. The initialization is performed in definition order within single translation unit. Compare its behavior to class constructor execution of global variables.

 

are vtables constructed by the time constructors are run?

vtables are generated before; as for class constructor of global variables.

 

can you initialize static (const) reference members and what's the syntax?

Hm, actually why not through initializers list? Any objection?

 

can you throw an object that's class is being statically constructed?

I am thinking about this use case, but I do not see your point. Can you elaborate a little bit more please?


Best Regards,

Mariusz

static class constructor.htm

k.saur...@gmail.com

unread,
Apr 18, 2018, 10:55:55 AM4/18/18
to ISO C++ Standard - Future Proposals
Same code if I run I get :

main.cpp:57:20: error: constructor cannot be static member function
         static Log()

Jake Arkinstall

unread,
Apr 18, 2018, 11:11:59 AM4/18/18
to std-pr...@isocpp.org
This group is for proposals that change the standard to add new capability. You won't find many posts here with code that actually works yet, just code that people want to work in the future.

Mariusz Moczala

unread,
Apr 18, 2018, 12:55:26 PM4/18/18
to ISO C++ Standard - Future Proposals
That's right. This is the proposal to C++ standard.
Nevertheless I am very happy that it is the feature which people need.
I see many modern languages having this static class constructors already. 

Thiago Macieira

unread,
Apr 19, 2018, 4:05:54 AM4/19/18
to std-pr...@isocpp.org
On Wednesday, 18 April 2018 09:55:26 PDT Mariusz Moczala wrote:
> That's right. This is the proposal to C++ standard.
> Nevertheless I am very happy that it is the feature which people need.
> I see many modern languages having this static class constructors already.

Then please explain what a static class constructor is and does, who needs it,
and how it improves developers' lives.

Mariusz Moczala

unread,
Apr 19, 2018, 6:37:46 AM4/19/18
to ISO C++ Standard - Future Proposals
Sure, with pleasure! lets call them SCC (Static Class Constructor) and SCD (Static Class Destructor)
for simplification.


WHAT IS IT?

SCC and SCD are special kind of constructor/destructor which is associathed with class (type) rather
than with the object. What is certain from developers point of view is that SCC is called only once
before entering the scope where corresponding type (class) is defined and SCD once after leaving it.
When type is defined in global scope SCC is called once before execution of main() function and SCD
once after.


WHO NEED IT?

Definitely those who write modern and header only libraries in C++. Every year more and more libraries
are created as header only code. In such code to initialize some content developers can for example
create a dedicated singleton class with special mechanisms for initialization, unfortunately user of
the library have to manually execute this initialization. Developers of the library can also provide
a lazy initialization, however not in every case it can be used. Using an object declared as a global
variable is a nightmare in this case. It have to be initialized in only one translation unit, so where
to put it? Definitely not in the header file as including it in many translation units will lead to
fail linking. And moreover, where to put initialization of static class members in header only code?


HOW IT IMPROVES DEVELOPERS LIVES?

And here comes elegant, single line solution with SCC and/or SCD. Declared/Defined as classic class
constructor but preceded with static keyword. It takes no arguments. As classical static function it
is not associated with any object, so the this keyword is not available here. Initialization of
static members can be done through initializers list of SCC. It is excelent place to execute early
initialization code. Through One Definition Rule (ODR is already in C++ standard) it solves all
complication related to linking.


I encourage you to read more in old proposal available here:

Andrey Semashev

unread,
Apr 19, 2018, 8:55:31 AM4/19/18
to std-pr...@isocpp.org
On 04/19/18 13:37, Mariusz Moczala wrote:
> Sure, with pleasure! lets call them SCC (Static Class Constructor) and
> SCD (Static Class Destructor)
> for simplification.
>
>
> WHAT IS IT?
>
> SCC and SCD are special kind of constructor/destructor which is
> associathed with class (type) rather
> than with the object. What is certain from developers point of view is
> that SCC is called only once
> before entering the scope where corresponding type (class) is defined
> and SCD once after leaving it.
> When type is defined in global scope SCC is called once before execution
> of main() function and SCD
> once after.

Since the constructor/destructor in this case does not
construct/destruct an object in this model, I don't see why it should be
a constructor/destructor in the first place. The whole involvement of a
type to define SCC/SCD looks like a kludge to me.

If you want a function called on program startup or termination, you'd
better look at standardizing
__attribute__((constructor))/__attribute__((destructor))[1]. You'd have
to present a rationale for why a global variable with a
constructor/destructor doesn't cut it and in the latter case - why
std::atexit doesn't cut it.

[1]:
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

> WHO NEED IT?
>
> Definitely those who write modern and header only libraries in C++.
> Every year more and more libraries
> are created as header only code. In such code to initialize some content
> developers can for example
> create a dedicated singleton class with special mechanisms for
> initialization, unfortunately user of
> the library have to manually execute this initialization. Developers of
> the library can also provide
> a lazy initialization, however not in every case it can be used. Using
> an object declared as a global
> variable is a nightmare in this case. It have to be initialized in only
> one translation unit, so where
> to put it? Definitely not in the header file as including it in many
> translation units will lead to
> fail linking. And moreover, where to put initialization of static class
> members in header only code?

I think, inline variables solved these problems. We still have issues
with global initialization order, but I don't see SCC/SCD solving them.
The mentioned above attributes do solve them to some extent, BTW.

Richard Hodges

unread,
Apr 19, 2018, 10:22:17 AM4/19/18
to std-pr...@isocpp.org
isn't this proposal the same as simply allowing:

class X {
  static bool init = initialise_class();
  static bool initialise_class() { ... }
};

?

Which I agree would be very useful, and indeed more versatile.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Dilip Ranganathan

unread,
Apr 19, 2018, 10:35:38 AM4/19/18
to std-pr...@isocpp.org
One other language where I have seen static constructors is C#. But its only used
to initialize static members and maybe perform some kind of one-time initialization
before an instance of that type could be created (the timing of /when/ it would be
run is a bit iffy though.)

Andrey Semashev

unread,
Apr 19, 2018, 10:57:19 AM4/19/18
to std-pr...@isocpp.org
On 04/19/18 17:22, Richard Hodges wrote:
> isn't this proposal the same as simply allowing:
>
> class X {
>   static bool init = initialise_class();
>   static bool initialise_class() { ... }
> };
>
> ?
>
> Which I agree would be very useful, and indeed more versatile.

Why not just initialize the static class members the usual way, with the
members' constructors? You can potentially leverage constexpr and make
the whole initialization a constant initialization.

Probably the only use case for initialise_class-style initialization is
building various process-wide tables or something like that. An empty
initializer class works fine for that use case, and I don't see how the
proposed feature improves on that.

Thiago Macieira

unread,
Apr 19, 2018, 3:10:51 PM4/19/18
to std-pr...@isocpp.org
On Thursday, 19 April 2018 03:37:46 PDT Mariusz Moczala wrote:
> I encourage you to read more in old proposal available here:
> http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0421r0.html

Thanks.

Sorry, but I'm not convinced. The paper lists the following advantages:


> There is no need to create dummy global variable to perform
initialization.

That's a non-issue.

> Each dummy global variable used in initialization have associated
> identifier and therefore is visible under IntelliSense. It becomes more
> difficult in navigation for projects using multiple dummy global
> variables.

Non-issue. You can easily hide the variables in a detail namespace.

Either way, both issues would be solved if we have the "discard identifier"
proposal accepted in one form or another.

> Static constructors allows to perform early initialization for
> headers-only libraries, where global variables cannot easily be used.

Isn't this solved by inline variables? The paper talks about it but does not
address why the use of inline variables would not obviate the need. I'd like
to ask for more exploration of the issue.

There's a side-point in the paper that suggests the static class constructor
could be the place to initialise the static members. This could help organise
code, but in the end it's not new functionality and the use-case already
works.
Reply all
Reply to author
Forward
0 new messages