33

Clang warns (when using -Weverything or Wglobal-constructors) about constructors for static objects.

warning: declaration requires a global constructor
      [-Wglobal-constructors]
A A::my_A; // triggers said warning
     ^~~~

Why is this relevant and how should one deal with this warning?

Simple example code:

class A {
  // ...
  static A my_A;
  A();
};

A A::my_A; // triggers said warning
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
Walter
  • 44,150
  • 20
  • 113
  • 196
  • 3
    Can we see the warning, please? – jrok Mar 29 '13 at 17:37
  • is this in one .h file? – yngccc Mar 29 '13 at 17:42
  • You have an object of A inside class A. How does this work? Doesn't this become recursive - even if the object is static. Though there is only one my_A & the recursiveness will not cause issues, I still can do `A a;` & then a.mY_A.my_A.my_A.my_A etc. – user93353 Mar 29 '13 at 17:55
  • 2
    @user93353 No. It's `static`. It's *declared* in `class A`, but it does not reside in each `class A`. – Drew Dormann Mar 29 '13 at 18:00
  • 4
    @DrewDormann - This program compiles `struct A { static A s; }; A A::s; int main() { A a; a.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s; }` - it's almost like a C++ joke. Why would someone want to have a static object inside itself? – user93353 Mar 29 '13 at 18:01
  • 4
    @user93353 A `static` object is part of the `class`, not part of an individual object of the class, i.e. **not** *inside itself*. Nonetheless, you can access it as if it is a member of an object: `A::s` and `A().s` refer to the same (and only) object (whether that is of the same type `A` or not). Having a `static` member of the same type is a way to implement a singleton. – Walter Mar 03 '18 at 00:46
  • @user93353 • I've seen that pattern sometimes used to create a set of static instances with fixed values. Conceptually, like an enum on steroids. Typically, the class constructors are private, so only the exposed statics are available for external use. – Eljay Aug 15 '18 at 12:32

3 Answers3

29

Here is a simpler case that triggers the same warning:

class A {
public:
  // ...
  A();
};

A my_A; // triggers said warning


test.cpp:7:3: warning: declaration requires a global constructor [-Wglobal-constructors]
A my_A; // triggers said warning
  ^~~~
1 warning generated.

This is perfectly legal and safe C++.

However for every non-trivial global constructor you have, launch time of your application suffers. The warning is simply a way of letting you know about this potential performance problem.

You can disable the warning with -Wno-global-constructors. Or you can change to a lazy initialization scheme like this:

A&
my_A()
{
    static A a;
    return a;
}

which avoids the issue entirely (and suppresses the warning).

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 22
    Are you sure the performance is the main issue? I would think that bigger problem might appear - since order of globals/statics initialization is undefined in C++, non-trivial global object might introduce in its constructor a dependency on another global object, leading to undefined behavior. – SomeWittyUsername Mar 29 '13 at 18:09
  • 2
    okay thanks. I think I got confused by the wording *global constructor*. Perhaps something like *construction at startup* would be more appropriate. – Walter Mar 29 '13 at 18:09
  • @icepack good point. This may indeed occur in my code, though I never yet encountered a problem ... – Walter Mar 29 '13 at 18:10
  • 3
    @icepack: Yes, I'm sure. The order of global constructors is partially defined. Those constructors appearing in the same translation unit are constructed in the order of appearance. Ordering between translation units is unspecified. And yes that can cause a problem. But no, that was not the motivation for introducing this warning. – Howard Hinnant Mar 29 '13 at 18:14
  • It would be nice if clang/gcc would tell you how to suppress the warning for one particular call-site in addition to how to disable the warning globally. I often find suppressing individual call-sites is very non-idiomatic and varies greatly from case to case. This little trick let me work around the problem tho so thanks. – Necro May 14 '13 at 18:17
  • *"This is perfectly legal and safe C++"* - [Static Initialization Order Fiasco](https://isocpp.org/wiki/faq/ctors) for the win! The C++ Committee has let the problem fester for 30 years. The committee is trying to get half pregnant. Sometimes what happens in translation units matters to them (like ODR), and sometimes it does not (like SIOF). (Or maybe they think all programs are made up of a single object file...). – jww Dec 03 '18 at 13:15
5

Solution from @Howard Hinnant avoid global constructor, but it do exit time destructor still. It can be found with option -Wexit-time-destructors

So Ideal solution can be based on CR_DEFINE_STATIC_LOCAL from http://src.chromium.org/svn/trunk/src/base/basictypes.h

A& my_A()
{
    static A &a = *new A;
    return a;
}
Maxim Kholyavkin
  • 4,463
  • 2
  • 37
  • 82
  • 2
    This code will create warnings from memory leak tools. – David Faure Mar 18 '14 at 16:14
  • 1
    of course! destructor will not be called for this code. – Maxim Kholyavkin Mar 19 '14 at 04:20
  • @DavidFaure Could the memory leak not be avoided by holding a `static unique_ptr` (instead of the `static A&`) inside `A::my_A()`? – Walter Feb 16 '15 at 09:36
  • 1
    @Walter: defining { static A a; return a; } would give the same results you suggested with unique_ptr – hauron Apr 08 '15 at 11:46
  • 1
    @hauron Why the solution proposed by Speakus is *not* the same as using a static object is described in [this paragraph of the C++ FAQ](https://isocpp.org/wiki/faq/ctors#construct-on-first-use-v2). A better but more complex solution (called [*Nifty Counter Idiom*](https://isocpp.org/wiki/faq/ctors#nifty-counter-idiom) by the FAQ) is missing an explanation, but I guess that this refers to the technique used to initialize `std::cout` and friends (see [`std::ios_base::Init`](http://en.cppreference.com/w/cpp/io/ios_base/Init)). – Max Truxa May 19 '15 at 20:29
  • @MaxTruxa Thank you for the find, I suppose a solution working around this problem, would be to wrap the static object in a shared_ptr, so any dependencies relying on it would hold a reference, saving it from getting destroyed "until the very last moment". And you get to keep your destructor executed. – hauron May 20 '15 at 11:47
  • I don't think a solution that generates worse code to avoid a warning is an "Ideal solution": https://godbolt.org/z/ejhv38YWc. Instead prefer https://clang.llvm.org/docs/AttributeReference.html#no-destroy – David Stone Dec 26 '21 at 17:05
3

If you can declare the constructor constexpr, that will suppress the warning (because this guarantees constant initialization). See https://godbolt.org/z/s3hY83jdr

David Stone
  • 26,872
  • 14
  • 68
  • 84