2

In my shared library I need to load some data into an unordered_map, and I try to do it in a function marked __ attribute__((constructor)). However I got the SIGFPE on every map operation. After some looking into stackoverflow I found that this means that unordered_map is uninitialized. This is quite unexpected and ununderstandable for me, because, at a glance, it violates C++ contracts. Anybody could help on how can I run this method after constructors were run? Here is a working example with my own constructor, which shows that it's not called:

#include <stdio.h>

class Ala {
    int i;
public:
    Ala() {
        printf("constructor called\n");
        i = 3;
    }

    int getI() {
        return i;
    }
};

Ala a;

__attribute__((constructor))
static void initialize_shared_library() {
    printf("initializing shared library\n");
    printf("a.i=%d\n", a.getI());
    printf("end of initialization of the shared library\n");
}

The outcome is

initializing shared library
a.i=0
end of initialization of the shared library
constructor called

however if one tries to use std::cout instead of printfs then it goes into SEGFAULTs immediately (because constructor of streams were not run)

pawel_j
  • 419
  • 4
  • 14
  • You could try using the [__attribute__((init_priority(123))](https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/C_002b_002b-Attributes.html#C_002b_002b-Attributes) syntax and give a lower number to `a` than this function – M.M Jun 05 '18 at 08:36
  • You need to specify a priority to ensure the right order of constructors. Better stay away from the compiler extension and use a vanilla c++ construct as suggested in the answer. – Goswin von Brederlow Jun 05 '18 at 08:37
  • "it violates C++ contracts" : of *course* it violates C++ contracts; you used a compiler extension - that means it isn't going to behave like standard C++. You need to read the documentation for the extension to see how it behaves. – Martin Bonner supports Monica Jun 05 '18 at 08:39
  • @MartinBonner unfortunately the documentation seems to be pretty threadbare, it does not cover things such as interaction with global objects without that attribute – M.M Jun 05 '18 at 08:41
  • I think that the order in which things happen here is undefined. It certainly doesn't seem to be documented. It's an old thread, but see: https://stackoverflow.com/questions/8433484/c-static-initialization-vs-attribute-constructor – Paul Sanders Jun 05 '18 at 08:41

3 Answers3

6

__attribute__((constructor)) is a compiler extension, and so you left the realms of standard C++. It looks like GCC's constructor functions are run before global initialization.

The way to fix it is to use another vanilla C++ construct, for example a global object whose initialization is properly sequenced by defining it in the same TU as your other global:

Ala a;

static void initialize_shared_library() {
    printf("initializing shared library\n");
    printf("a.i=%d\n", a.getI());
    printf("end of initialization of the shared library\n");
}

static int const do_init = (initialize_shared_library(), 0);
Quentin
  • 62,093
  • 7
  • 131
  • 191
1

If you use a function that returns the static local variable, the variable will be initialized the first time the function gets called. See: When do function-level static variables get allocated/initialized?

struct Ala {
   // Your code here
   static Ala& get_singleton();
};

Ala& Ala::get_singleton() {
   static Ala singleton;
   return singleton;
}

static void initialize_shared_library() {
    Ala& a = get_singleton();
    printf("initializing shared library\n");
    printf("a.i=%d\n", a.getI());
    printf("end of initialization of the shared library\n");
}

As others have said, it is usually better to encapsulate all the initialization process in a object and let the constructor do the work for you (the body of the constructor is executed after all the members of the class are initialized).

Jorge Bellon
  • 2,901
  • 15
  • 25
0

If you just want to run something after a is initialized there are several ways to do that without leaving Standard C++; here is one:

struct Ala2 : Ala
{
    Ala2()
    {
         // your init code here
    }
};

Ala2 a;
M.M
  • 138,810
  • 21
  • 208
  • 365