Question About Static Initialization Fiasco (Confusion in isocpp FAQ) - c++

There is a great FAQ(isocpp) just demonstrates why we potentaily cannot we use static object instead of static pointer to avoid Fiasco problem. I came across a sentence in the answer that gave me a headache
.... By changing the declaration from static X* xp = new X();
to static X xp;, we still correctly handle the initialization
situation but we no longer handle the deinitialization situation. For
example, if there are 3 static objects, say a, b and c, that use ans
during their destructors, the only way to avoid a static
deinitialization disaster is if xp is destructed after all three.
main.cpp
#include "x.h" // struct X { X(int); void f(); };
X& x(int i)
{
static X xp{ i };
return xp;
}
struct Y
{
Y(int);
private: int m_y;
};
Y::Y(int i) {
x(i).f();
}
other.cpp
Y y{ 20 };
struct X {
X(int);
void f();
private: int m_x;
};
X::X(int j): m_x(j) {};
void X::f() { std::cout << m_x << std::endl; }
Then they continue with:
The point is simple: if there are any other static objects whose
destructors might use xp after xp is destructed, bang, you’re dead.
I just cannot understand how this problem can happen. I need a practical example that demonstrates how this problem can occur.

Related

How to return a class instance on the heap, when the relevant ctor is private?

Suppose I have this struct
struct MyStruct {
static MyStruct Create(int x) {
return { x*2, x>3 };
}
MyStruct(const MyStruct& c) = delete; // no copy c'tor
private:
MyStruct(int a_, bool b_) : a(a_), b(b_) {} // private c'tor -- can't use new
const int a;
const bool b;
};
Edit: I deleted the copy constructor. This is simplified example of some classes I have in my codebase where they don't have copy c'tors.
I can get an instance on the stack like so:
int main() {
auto foo = MyStruct::Create(2);
return 0;
}
But suppose I need a pointer instead (or unique_ptr is fine), and I can't change the implementation of MyStruct, how can I do that?
You could wrap MyStruct in another class, which has a MyStruct member. Here's a minimal version of that:
class Wrapper {
public:
MyStruct ms;
Wrapper(int x) : ms(MyStruct::Create(x)) { }
};
which you can use like so:
int main() {
MyStruct::Create(2);
std::make_unique<Wrapper>(2);
}
This code will not trigger any copies nor moves - because of copy elision (see: What are copy elision and return value optimization?).
You can then add any other constructors and methods you like to such a wrapper, possibly forwarding some of the method calls to the ms member. Some might choose to make ms protected or private.
Is this what you're looking for?
auto baz = std::make_unique<MyStruct>( MyStruct::Create(2) ); // unique pointer
A comment rather than an answer, to avoid confusion for future readers.
I can get an instance on the stack like so:
int main() {
auto foo = MyStruct::Create(2);
return 0;
}
Note that this is only true as of C++17 and guaranteed copy elision, whereas the program is ill-formed is C++14, as even if the copy may be elided, the initialization of foo is copy-initialization from a temporary (in C++17: the temporary is never materialized).
One more way to do it:
struct ChildStruct : public MyStruct {
ChildStruct(int x) : MyStruct(MyStruct::Create(x))
{}
};
int main() {
MyStruct *foo1 = new ChildStruct(2);
return 0;
}
C style solution. I am not sure that this is not UB, but for simple struct with 2 integer fields it should work.
int main() {
auto foo = MyStruct::Create(2);
MyStruct *p = (MyStruct*)malloc(sizeof(MyStruct));
memcpy(p, &foo, sizeof(MyStruct));
//...
free(p);
return 0;
}

Uninitialized value when dealing with shared_ptr

I'm sure this is very simple, but I'm rather new to smart pointers, and I couldn't find an answer to this.
Scenario is very simple:
I have a class A, that holds a shared_ptr to some object X:
class A{
shared_ptr<const X> _asX;
}
now after a series of function calls, I'm creating a new object of type B, that also holds this X. something like:
class B {
private:
shared_ptr<const X> _bsX;
public:
B(): _bsX(nullptr) // - maybe this is problematic {}
foo(shared_ptr<const X>& x)
{
_bsX = x;
// The line above gives me undefined behavior,
// and when I run valgrind I get "Conditional jump or move
// depends on uninitialized value(s)",
// telling me this is not the correct way to do things.
}
Note that it is deliberate the foo really sets the value of _bsX and not the constructor.
So as stated above - depending on the compiler, I something get segmentation faults - which usually means some value was not initialized, and later confirmed by valgrind.
So what should I do - I've tried using 'reset' etc. but I got so confused I'm asking for your help.
Could it be the const ? or the pass by reference ? or the '=' operator.
And while we're at it - should I be passing X with its wrapper (the shared_ptr) to foo, or should I pass the raw pointer, and then make it shared ? if so - could you please give an example. I tried that as well, and got errors.
Ok, I found the problem, and it's no related to smart pointers at all, but since I'm new to this - I thought it might be.
I'll leave this answer for future references. This is what I did (simplified):
class A{
private:
shared_ptr<const int> _num;
public:
A()
{
_num = make_shared<const int>(5);
}
const shared_ptr<const int>& getNum() const {return _num; }
void printNum()
{
cout << *_num.get() << endl;
}
};
class B
{
public:
struct C{
C() : _num(nullptr){}
void boo(shared_ptr<const int> & num) { _num = num;}
shared_ptr<const int> _num;
};
B() {}
void foo(shared_ptr<const int>& num)
{
cs.reserve(2);
for (uint32_t i = 0; i < 2 ; ++i) {
cs.push_back(C()); // This was missing.
cs[i].boo(num);
}
}
void printCNum()
{
for (C c : cs) {
cout << *c._num.get() << endl;
}
}
private:
vector<C> cs;
};
int main()
{
A a{};
shared_ptr<const int> xx = a.getNum();
B b{};
b.foo(xx);
a.printNum();
b.printCNum();
}
Silly me, I thought that when you reserve a vector of Objects (not pointers/references) it also calls their constructor. It turn out it's not. Specifically, I increased the capacity of the vector, but not its size.

C++ constructor of an object which is part of another object

That is not a duplicate. Please read carefully. There are two variables x (of type int and X) and one member is actually declared private, which is used in a constructor. It is about understanding the constructor process in this very specific case.
I am doing a C++ course and I understand the following example that was given. It is about constructors.
#include <iostream>
using namespace std;
class Element {
int value;
public:
Element(int val) {
value = val;
cout << "Element(" << val << ") constructed!" << endl;
}
int Get(void) {
return value;
}
void Put(int val) {
value = val;
}
};
class Collection {
Element el1, el2;
public:
Collection(void) : el2(2), el1(1) {
cout << "Collection constructed!" << endl;
}
int Get(int elno) {
return elno == 1 ? el1.Get() : el2.Get();
}
int Put(int elno, int val) {
if (elno == 1) el1.Put(val);
else el2.Put(val);
}
};
int main(void) {
Collection coll;
return 0;
}
Then they mentioned the following
...
We should also add that there is the following alternation for that
case: when the constructor is divided between the declaration and the
definition, the list of alternative constructors should be associated
with the definition, not the declaration.
It means that the following snippet is correct:
class X {
public:
X(int x) { };
};
class Y {
X x;
public:
Y(int x);
};
Y::Y(int x) : x(1) { };
Can someone explain? Is it really correct? And if yes, how to interpret that? Y has a one-parameter constructor, but no value is passed. x(1) is probably the constructor for the field X x in Y. Is the value of 1 (of x(1)) then passed to Y(int x) automatically although it is declared private in Y?
In the second code snippet, there is no construction actually going on—it's just a definition of the classes and constructors. The only "special" thing about it is that the body of Y's constructor is defined outside the class; it could be in a different file, for example. In this case, it's no different from putting the body directly into the class1:
class Y {
X x;
public:
Y(int x) : x(1) {}
};
When this constructor of Y is invoked, it constructs the member variable x by passing 1 to the X constructor taking int. The constructor of Y doesn't do anything else, i.e. it ignores its own parameter.
The syntax Y::Y used in the original code snippet is standard syntax for defining a member function outside of the class definition. For a non-constructor, it would look like this:
class Foo
{
int bar() const;
};
int Foo::bar() const
{
return 42;
}
1 With the slight difference that when put directly into the class definition, the function is implicitly inline (can be present in more than one translation unit).

Why can't non-static data members be constexpr?

This is valid code:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
const int xVal { 0 };
const int yVal { 0 };
};
But here I'd really like to declare xVal and yVal constexpr--like this:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
constexpr int yVal { 0 }; // error!
};
As indicated, the code won't compile. The reason is that (per 7.1.5/1), only static data members may be declared constexpr. But why?
Think about what constexpr means. It means that I can resolve this value at compile time.
Thus, a member variable of a class cannot itself be a constexpr...the instance that xVal belongs to does not exist until instantiation time! The thing that owns xVal could be constexp, and that would make xVal a constexpr, but xVal could never be constexpr on its own.
That does not mean that these values can't be const expression...in fact, a constexpr instance of the class can use the variables as const expressions:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
int xVal { 0 };
int yVal { 0 };
};
constexpr S s;
template <int f>//requires a constexpr
int foo() {return f;}
int main()
{
cout << "Hello World" << foo<s.xVal>( )<< endl;
return 0;
}
Edit: So there has been alot of discussion below that reviewed that there was a couple of implied questions here.
"why can't I enforce all instances of a class to be constexpr by declaring its members to be constexpr?"
Take the following example:
//a.h
struct S;
struct A {std::unique_ptr<S> x; void Foo(); A();/*assume A() tries to instantiate an x*/}
//main.cpp
int main(int argc, char** argv) {
A a;
a->foo();
}
//S.h
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
constexpr int yVal { 0 };
};
The definition of A and S could be in completely different compilation units, so the fact that S must be constexpr may not be known until link time, especially if the implementation of A is forgotten. Such ambiguous cases would be hard to debug and hard to implement. Whats worse is that the interface for S could be exposed entirely in a shared library, COM interface, ect...This could entirely change all the infrastructures for a shared library and that would probably be unacceptable.
Another reason would be how infectious that is. If any of the members of a class were constexpr, all the members (and all their members) and all instances would have to be constexpr. Take the following scenario:
//S.h
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
int yVal { 0 };
};
Any instance of S would have to be constexpr to be able to hold an exclusively constexpr xval. yVal inherently becomes constexpr because xVal is. There is no technical compiler reason you can't do that (i don't think) but it does not feel very C++-like.
"OK, but i REEAAALLLY want to make all instances of a class constexpr. What is the technical limitation that prevents me from doing that".
Probably nothing other than the standards committee didn't think it was a good idea. Personally, I find it having very little utility...I don't really want to define how people use my class, just define how my class behaves when they use it. When they use it, they can declare specific instances as constexpr (as above). If I have some block of code that I would like a constexpr instance over, I'd do it with a template:
template <S s>
function int bar(){return s.xVal;}
int main()
{
cout << "Hello World" << foo<bar<s>()>( )<< endl;
return 0;
}
Though I think you'd be better off with a constexpr function that could be used both in the restrictive an non restrictive ways?
constexpr int bar(S s) { return s.xVal; }

Automatic determination of the constructor initialization list by the compiler?

I was asking myself (and couldn't find an answer) if the modern C++ compilers could check into the body of the constructors to see if they could infer the initialization list, instead of letting the developer specifying it?
As an example, consider the following code:
MyClass::MyClass (Obj o)
{
_o = o;
}
Can the compiler automatically translate it into:
MyClass::MyClass (Obj o) : _o(o)
{}
Thanks
This is not possible as it completely changes the semantics of the program in the general case. Some of the examples:
// Order of evaluation:
struct Foo {
int a, b;
Foo() : b(a) { a = 1; } // differs from Foo() : a(1), b(a) {}
};
// Legality of the operation:
struct X { explicit X(int x); };
struct Foo {
X x;
Foo() { x = 5; } // Ill formed, while Foo() : x(5) is well formed
};
// Different effects even if allowed
struct X {
X(int) { std::cout << "int\n"; }
X() { std::cout << "default\n"; }
X& operator=(int) { std::cout << "assignment\n"; }
};
struct Foo {
X x;
Foo() { x = 5; } // prints: default\nassignment\n
// Where Foo() : x(5) {} // prints: int\n
};
At the language level both operations are completely different and cannot be transformed. That being said, the optimizer might be able to produce the exact same code for both if they are truly equivalent.
No, because the semantics are different. The following direct-initializes the member _o from o:
MyClass::MyClass (Obj o) : _o(o)
{}
On the other hand, the following default-initializes _o and then assigns the value of o to it:
MyClass::MyClass (Obj o)
{
_o = o;
}
In some cases there really might be no effective difference, such as if Obj is actually int. In cases where there is no effective difference, perhaps the compiler will generate the same code for both cases, but then again, maybe not. Depends how clever the optimizer is.
They are checking (if member variables needs to be created with parameters).
For example, this :
struct A {
A( int ) {}
};
struct B {
B(){ a = A(3); }
A a;
};
is going to fail with an error.
On the other hand, some types do not need parameters to be initialized. For example :
struct A
{
A(){
v = 3;
}
int v;
};
The standard doesn't require the compiler to issue a warning, but some compilers are capable of doing it (gcc has -Weffc++ flag).
Also, there are static code analysis tools to warn about such "errors".