I have some code from a project which doesn't seem to be working.
I am trying to make a deque (of a struct) which is a static member of a class. The skeleton/basic code is as follows (I have retained all datatypes - my_typedef_fn is a data type got by typedef-ing a function pointer) :
1.h file :
class A {
struct Bstruct {
char * b_name;
my_typedef_fn b_func;
}
static std::deque<Bstruct> a_deque;
static void func();
}
1.cpp file :
std::deque<A::Bstruct> A::a_deque;
void A::func(char * name, my_typedef_fn fn) {
a_deque.push_front((Bstruct) {name, fn} ); // <<<< segfault !
}
From my understanding - The .h file just declares the stuff (as usual) - The first line in the .cpp initializes the static member a_deque - The function func adds stuff to the deque using push_back
But I get a Segmentation Error at the line where push_front is called (found this using gdb).
Also, when I print a_deque.size() before push_front I get 4294967264 before the SEGFAULT And when I count the number of elements in deque using a for loop :
int counter = 0
for( std::deque<Bstruct> it = a_deque.begin(); it != a_deque.end(); it++, counter++ );
my counter shows 0 elements to be in the
So, I do not understand why I get a segfault nor why the .size() is a large garbage number
-- EDIT 1 -- Adding the way the functions are called :
2.cpp
#include "1.h"
void fn1() {
// some code
}
A::func("abc", fn1);
It is complied with the commands :
g++ -c -w -fpermissive -o 1.o 1.cpp
g++ -c -w -fpermissive -o 2.o 2.cpp
g++ -o final 1.o 2.o
It is normally not possible to simply call a function in global scope, like you're showing in 2.cpp
. But you mentioned the code is old, so maybe it's a pre-standard thing, or an extension.
Anyway, you've shown the function is being called in 2.cpp
, while the static data member a_deque
is defined in 1.cpp
. This means you're probably falling prey to static initialisation order fiasco. Globals (such as static data members, and apparently this weird free-standing function call as well) are initialised/executed in order they appear within one translation unit (= .cpp
file), but their order across translation units is unspecified.
Which means it's perfectly possible for A::func()
to access a_deque
before the constructor of a_deque
has run, which could very possibly lead to a segfault (as the internal data members of the deque have zero or possibly even random values).
To fix this, you'll have to get rid of this situation somehow. One option would be to move all global code which can access a_deque
into 1.cpp
and place it after the definition of a_deque
.
An alternative would be to replace a_deque
with a function-scope static variable, which is guaranteed to be initialised before first use:
1.h
class A {
struct Bstruct {
char * b_name;
my_typedef_fn b_func;
}
static std::deque<BStruct>& a_deque();
static void func();
}
1.cpp
#include "1.h"
std::deque<A::BStruct>& A::a_deque()
{
static std::deque<BStruct> d;
return d;
}
void A::func(char * name, my_typedef_fn fn) {
a_deque().push_front((Bstruct) {name, fn} ); // <<<< hopefully no more segfault
}