Apr 10, 2015 at 4:51pm UTC
Hey there,
I have this little program and allready don't know what's going on here...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#include <iostream>
#include <vector>
class Base {};
std::vector<Base*> elements;
template <typename T>
class A : public Base
{
public :
A()
{
std::cout << "A-Ctor" << std::endl;
elements.push_back(&(T::get()));
}
};
class B : public A<B>
{
public :
B() { std::cout << "B-Ctor" << std::endl; }
static B& get() { static B b; return b; }
};
int main(void )
{
B b;
std::cout << elements.size() << std::endl;
}
http://cpp.sh/2ku2z
I thought it would go like this ...
- B b
| - calls B-Constructor
| | - calls A<B>-Constructor.
| | | - calls
std::cout << "A-Ctor" << std::endl;
| | | - calls B::get()
| | | | - calls B-Constructor for the static variable
| | | | | - calls A<B>-Constructor
| | | | | | - calls
std::cout << "A-Ctor" << std::endl;
| | | | | | - calls B::get() (no B constructor because of static variable)
| | | | | | - pushes the retreived pointer to the std::vector
| | | | | - calls
std::cout << "B-Ctor" << std::endl;
| | | - Inserts the retreived pointer to the std::vector
| | - calls
std::cout << "B-Ctor" << std::endl;
-
std::cout << elements.size() << std::endl;
... but some reason it just prints A-Ctor twice and then does nothing and the program does not stop.
What did i miss here?
Edit: added a few std::couts to find out more.
For some reason it stops at the second
static B b;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include <iostream>
#include <vector>
#include <memory>
class Base { public : Base() { std::cout << "Base-Ctor" << std::endl; }};
std::vector<Base*> elements;
template <typename T>
class A : public Base
{
public :
A()
{
std::cout << "A-Ctor begin" << std::endl;
elements.push_back(&(T::get()));
std::cout << "A-Ctor end" << std::endl;
}
};
class B : public A<B>
{
public :
B() { std::cout << "B-Ctor" << std::endl; }
static B& get()
{
std::cout << "create static" << std::endl;
static B b;
std::cout << "return static" << std::endl;
return b;
}
};
int main(void )
{
B b;
std::cout << elements.size() << std::endl;
}
http://cpp.sh/764k
Base-Ctor
A-Ctor begin
create static
Base-Ctor
A-Ctor begin
create static
Last edited on Apr 10, 2015 at 4:59pm UTC
Apr 10, 2015 at 5:00pm UTC
In B::get, you are creating a static B, effectively constructing another B object.
Afterwards, this static B object calls A constructor (which is why you see two A constructors in the log). This static element's A constructor calls B::get again, leading to ambiguity (is the static object initialized? Will it recursively construct itself?)
I'm pretty sure the behavior is only defined until the second A constructor.
Apr 10, 2015 at 5:15pm UTC
I though static variables are only initialized once?
If that wouldn't be defined behaviours then static variables are pretty much the worst c++ feature...
edit: never mind that (see below)
In functions they are to be only initialized once, that's their purpose (i think)
This works fine...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include <iostream>
int & ifactory()
{
static int i;
return i;
}
int main()
{
int & i1 = ifactory();
i1 = 10;
int & i2 = ifactory();
i2 = 20;
std::cout << i1 << ' ' << i2 << std::endl; // 20 20
}
edit: Oh no...
In my example, the static object's constructor hasn't reached it's end yet so it may be like you say, that the object may or may not be initialized at that moment and the behaviour is undefined :(
Last edited on Apr 10, 2015 at 5:20pm UTC
Apr 10, 2015 at 5:39pm UTC
That's exactly the issue, referring to itself via another object is undefined behaviour (if the object hasn't beenfully constructed).
Perhaps you should push_back(this)?
Apr 10, 2015 at 6:02pm UTC
The issue is infinite recursion. It crashes with GCC:
http://ideone.com/0KWkhe terminate called after throwing an instance of '__gnu_cxx::recursive_init_error'
what(): std::exception
Get rid of your static
get function and take SGH's suggestion.
A doesn't even have to be a template.
Last edited on Apr 10, 2015 at 6:03pm UTC
Apr 10, 2015 at 6:42pm UTC
Perhaps you should push_back(this)?
Hooooraaaaaaay!!!!! :DDDDD
yeah, that works perfectly ^.^
Thank you <333
The issue is infinite recursion. It crashes with GCC:
thanks for confirming :)
A doesn't even have to be a template.
Well, it's not the concrete example but in my programm I need it to be a template.
Last edited on Apr 10, 2015 at 6:43pm UTC