Are objects created before setjmp destructed? - c++

In jpeglib, one has to use setjmp/longjmp to implement custom error handling.
There are lots of resources where it is said that setjmp/longjmp do not play well with c++ (for example answers in this question tell they do go along with RAII), but the answers to this question say that the destructor is called.
I have this example (taken from here and modified a bit):
#include <iostream>
#include <csetjmp>
std::jmp_buf jump_buffer;
struct A
{
A(){std::cout<<"A()"<<std::endl;}
~A(){std::cout<<"~A()"<<std::endl;}
};
void a(int count)
{
std::cout << "a(" << count << ") called\n";
std::longjmp(jump_buffer, count+1); // setjump() will return count+1
}
int main()
{
// is this object safely destroyed?
A obj;
int count = setjmp(jump_buffer);
if (count != 9) {
a(count);
}
}
In this example, the destructor is called (as I expected), but is it the standard behaviour? Or is it compiler's extension, or simple UB?
The output:
A()
a(0) called
a(1) called
a(2) called
a(3) called
a(4) called
a(5) called
a(6) called
a(7) called
a(8) called
~A()

It can be undefined behaviour depending on whether or not destructors would be called were an exception to execute the same transfer of control. In C++03. From section 18.7 Other runtime support, paragraph 4:
The function signature longjmp(jmp_buf jbuf, int val) has more restricted behavior in this International Standard. If any automatic objects would be destroyed by a thrown exception transferring control to another (destination) point in the program, then a call to longjmp(jbuf, val) at the throw point that transfers control to the same (destination) point has undefined behavior.
There's similar language in c++11:
The function signature longjmp(jmp_buf jbuf, int val) has more restricted behavior in this International Standard. A setjmp/longjmp call pair has undefined behavior if replacing the setjmp and longjmp by catch and throw would invoke any non-trivial destructors for any automatic objects.
However, there appear to be no destructors that are called in transition for this particular piece of code, so I believe it's safe.
Now, if you were to change the code to move the creation to after the setjmp, that becomes undefined behaviour. In my setup (gcc 4.4.5 under Debian), the following code (with everything else identical to your question):
int main() {
int count = setjmp (jump_buffer);
A obj;
if (count != 4) a (count);
}
results in the output:
A()
a(0) called
A()
a(1) called
A()
a(2) called
A()
a(3) called
A()
~A()
and you can see the destructor is not being called as part of the jump although, being undefined, it may be on some systems.
The bottom line is, you shouldn't be jumping from region A to region B where the equivalent throw/catch would properly destruct an object, because there's no guarantee the longjmp will call the destructor.
Actually, there are some who would say you shouldn't use setjmp/longjmp in C++ at all, and I tend to lean that way myself. I have a hard time seeing a need for that even in C.
I think I used it once in my entire career (and that's a long career), to implement co-operative threading in Turbo C under MS-DOS. I can't think of one other time I've ever used it. Not to say there aren't any uses, but they'd be pretty rare.

Related

std::unique_ptr, pimpl and object lifetime

The following example compiles with both gcc 11 on Linux (GNU STL) and clang 12 on FreeBSD (Clang STL). On Linux, it runs and prints values 1 and 2. On FreeBSD, it prints value 1 and then crashes with a SEGV. I don't quite understand the object lifetimes -- so the whole thing may be UB and the runtime behavior might not be relevant. I do know that the implementation of std::unique_ptr between those two STLs differs in an important way: Clang STL resets the internal pointer of a std::unique_ptr to nullptr at the start of the destructor, while GNU STL leaves the pointer alone.
#include <iostream>
#include <memory>
struct C {
struct Private {
C* m_owner;
int m_x;
Private(C* owner) : m_owner(owner), m_x(0) {}
~Private() { m_owner->cleanup(); }
void cleanup() { std::cout << "Private x=" << ++m_x << '\n'; }
};
std::unique_ptr<Private> d;
C() { d = std::make_unique<Private>(this); }
~C() = default;
void cleanup() { d->cleanup(); }
};
int main(int argc, char **argv)
{
C c;
c.cleanup(); // For display purposes, print 1
return 0; // Destructors called, print 2
}
Output on FreeBSD:
Private x=1
Segmentation fault (core dumped)
and a snippet of backtrace:
* thread #1, name = 'a.out', stop reason = signal SIGSEGV: invalid address (fault address: 0x8)
frame #0: 0x00000000002032b4 a.out`C::Private::cleanup() + 52
a.out`C::Private::cleanup:
-> 0x2032b4 <+52>: movl 0x8(%rax), %esi
My reason for thinking this might be UB is this:
at return 0, c's lifetime is ending.
the destructor ~C() runs. Once the body (defaulted) of the destructor is done, the lifetime of the object is over and using that object is UB.
now the destructors for sub-objects (member-objects?) of the object run.
the destructor ~std::unique_ptr<Private> runs. It runs the destructor for the held object.
the destructor ~Private() uses a pointer to a no-longer-alive object m_owner to call a member function.
I'd appreciate an answer that points out if this understanding of object lifetimes is correct.
If it's not UB, then there's a separate quality-of-implementation issue (or I should check the d-pointer before calling methods on it, but that seems a bit derpy for a pimpl; then we get if(d)d->cleanup() which is needed with one STL implementation and which is a useless check in another).
In the interest of posing a single question: does this code exhibit UB in the statement m_owner->cleanup() (line 9) during the destruction of object c ?
Yes, the lifetime of the object that m_owner refers to has already ended and it's destructor call completed when m_owner->cleanup(); is called. The call is therefore UB.

What happens when a constructor function calls itself in VS2013?

class IA
{
public:
virtual void Print() = 0;
}
IA* GetA();
class A : public IA
{
public:
int num = 10;
A()
{
GetA()->Print();
}
void Print()
{
std::cout << num << std::endl;
}
}
IA* GetA()
{
static A a;
return &a;
}
int main()
{
GetA();
std::cout << "End" << std::endl;
getchar();
return 0;
}
Obviously, class A's constructor function calls itself.
"static A a" will get stuck in a loop.
On VS2013, this code can get out from the loop and print "End" on the console.
On VS2017, this code gets stuck in a loop.
**What does VS2013 do for this code?
Nothing in particular has to happen. According to the C++ standard:
[stmt.dcl] (emphasis mine)
4 Dynamic initialization of a block-scope variable with static storage
duration or thread storage duration is performed the first time
control passes through its declaration; such a variable is considered
initialized upon the completion of its initialization. If the
initialization exits by throwing an exception, the initialization is
not complete, so it will be tried again the next time control enters
the declaration. If control enters the declaration concurrently while
the variable is being initialized, the concurrent execution shall wait
for completion of the initialization. If control re-enters the
declaration recursively while the variable is being initialized, the
behavior is undefined. [ Example:
int foo(int i) {
static int s = foo(2*i); // recursive call - undefined
return i+1;
}
 — end example ]
The statement I emboldened is exactly what happens in your program. It's also what the standard's example shows as undefined. The language specification says an implementation can do whatever it deems appropriate. So it could cause an infinite loop, or it may not, depending on the synchronization primitives your implementation uses to prevent concurrent reentry into the block (the initialization has to be thread safe).
Even before C++11, the behavior of recursive reentry was undefined. An implementation could do anything to make sure an object is initialized only once, which in turn could produce different results.
But you can't expect anything specific to happen portably. Not to mention undefined behavior always leaves room for a small chance of nasal demons.
The behaviour is undefined. The reason it "worked" in Visual Studio 2013 is that it didn't implement thread safe initialisation of function statics. What is probably happening is that the first call to GetA() creates a and calls the constructor. The second call to GetA() then just returns the partially constructed a. As the body of your constructor doesn't initialise anything calling Print() doesn't crash.
Visual Studio 2017 does implement thread safe initialisation. and presumably locks some mutex on entry to GetA() if a is not initialised, the second call to GetA() then encounters the locked mutex and deadlocks.
Note in both cases this is just my guess from the observed behaviour, the actual behaviour is undefined, for example GetA() may end up creating 2 instances of A.

why does the standard let me free-store allocate classes without destructors?

If you have a class without a destructor:
struct A {
~A() = delete;
};
The standard does not let me "locally" allocate an instance of that class:
int main()
{
A a; //error
}
But it seems like it is ok if I allocate that on free-store:
int main()
{
a *p = new A();
}
As long as I dont call delete on that pointer:
int main()
{
a *p = new A();
delete p; //error
}
So my question is, why does the standard let me have a class without a destructor if I allocate it on free-store? I would guess there are some use cases for that? But what exactly?
So my question is, why does the standard let me have a class without a destructor if I allocate it on free-store?
Because that's not how standard features work.
The = delete syntax you're talking about was invented to solve a number of problems. One of them was very specific: making types that were move-only or immobile, for which the compiler would issue a compile-time error if you attempted to call a copy (or move) constructor/assignment operator.
But the syntax has other purposes when applied generally. By =deleteing a function, you can prevent people from calling specific overloads of a function, mainly to stop certain kinds of problematic implicit conversions. If you don't call a function with a specific type, you get a compile-time error for calling a deleted overload. Therefore, =delete is allowed to be applied to any function.
And the destructor of a class qualifies as "any function".
The designed intent of the feature was not to make types which would be non-destructible. That's simply an outgrowth of permitting =delete on any function. It's not design or intent; it simply is.
While there isn't much use to applying =delete to a destructor, there also isn't much use in having the specification to explicitly forbid its use on a destructor. And there certainly isn't much use in making =delete behave differently when applied to a destructor.
With this:
A a;
You will call the destructor upon exiting the scope (and you have deleted the destructor, hence the error). With this:
A *a = new A();
You simply don't call the destructor (because you never use delete). The memory is cleaned up at the programs completion, but you are essentially guaranteeing a memory leak.
There is no reason for c++ to disallow this behavior because this would create a very specific case to program into a compiler. For example, c++ doesn't disallow this:
int *p; *p = 5;
Even though this is obviously bad, and will always be bad. It is up to the programmer to ensure they don't do this.
There is no reason that you should delete your destructor because it is not a useful behavior.
In a multi-threaded environment, you may be sharing the non-destructed class between threads.
If the thread that allocates memory terminates, there is no reason a pointer to that allocated memory couldn't still be in use by another thread.
The standard implies that a constructed object with dynamic storage duration does not qualify for destructor invocation.
12.4 Destructors [class.dtor]
A destructor is invoked implicitly
— for a constructed object with static storage duration at program termination,
— for a constructed object with thread storage duration
at thread exit,
— for a constructed object with automatic
storage duration when the block in which an object is created
exits,
— for a constructed temporary object when its
lifetime ends.
We can see the benefits of this through a basic memory sharing example between threads:
#include <thread>
#include <iostream>
//shared object
struct A {
void say_hello(){ std::cout << ++value << '\n'; }
~A() = delete;
int value;
};
//two threads
void creator();
void user(A* a);
//the creator allocates memory,
//gives it to another thread (via pointer),
//and then ends gracefully.
//It does not attempt to implicitly call the destructor.
//Nor would we want it to for allocated memory we are sharing.
void creator(){
A* a = new A();
a->value = 0;
std::thread t(user, a);
t.detach();
}
//The user recieves a pointer to memory,
//and is free to continue using it
//despite the creator thread ending
void user(A* a){
while(1){
a->say_hello();
}
}
//main->creator->user
int main(){
std::thread t(creator);
while(1){}
}

Calling copy constructor on yourself

I am curious about what is happening in this code I wrote almost by mistake:
#include <iostream>
class Test
{
public:
Test() {
std::cout << "Default constructor";
a= 10;
}
int a;
};
int main() {
Test obj(obj);
std::cout << obj.a << std::endl;
}
It compiles in gcc without warnings of any kind (using -Wall -Werror).
Executing it only prints garbage.
If I am not mistaken, this is calling the implicit copy-constructor on itself, without ever initialising. I am curious about what the copy-constructor would do in such a situation, but gdb will not stop in that line (breakpoints set to that line jump to the next one).
Everything breaks if "complex" attributes are added to the class (like a std::string), probably because of how the '=' operator is overloaded for such classes.
Is my hypothesis correct? Why doesn't gdb stop in that line? Why no warnings when calling a copy constructor with an uninitialised object?
Since you have a member variable of type int, whose indeterminate value is copied to itself, the code is technically Undefined Behavior.
However, in practice, with current computers nothing bad will happen. But on the third hand, nothing good happens either.
Regarding warnings, that's a Quality Of Implementation issue. The C++ standard has nothing to say about that.

Destructor not invoked when an exception is thrown in the constructor

Why is the destructor not invoked in this code?
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; throw; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
int main()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
std::cout << myinst->increment() << '\n';
std::cout << myinst->increment() << '\n';
}
EDIT
From the answers, In understand that when an exception happens in the constructor, destructor will not be invoked. But if the exception happens in the main(), ie after the MyClass object is fully instantiated, will the MyClass destructor be invoked? If not, then why it is a smart pointer?
Adding the code
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
int main()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
std::cout << myinst->increment() << '\n';
std::cout << myinst->increment() << '\n';
}
Output:
MyClass Allocated
terminate called after throwing an instance of 'int'
Aborted
A C++ object's lifetime begins only after its constructor completes successfully.
Since the exception was thrown before constructor call was complete you don't have an complete object and hence no destructor.
Herb Sutter explains this nicely, to quote him:
Q: What does emitting an exception from a constructor mean?
A: It means that construction has failed, the object never existed, its lifetime never began. Indeed, the only way to report the failure of construction -- that is, the inability to correctly build a functioning object of the given type -- is to throw an exception. (Yes, there is a now-obsolete programming convention that said, "if you get into trouble just set a status flag to 'bad' and let the caller check it via an IsOK() function." I'll comment on that presently.)
In biological terms,
conception took place -- the constructor began -- but despite best efforts it was followed by a miscarriage -- the constructor never ran to term(ination).
Incidentally, this is why a destructor will never be called if the constructor didn't succeed -- there's nothing to destroy. "It cannot die, for it never lived." Note that this makes the phrase "an object whose constructor threw an exception" really an oxymoron. Such a thing is even less than an ex-object... it never lived, never was, never breathed its first. It is a non-object.
We might summarize the C++ constructor model as follows:
Either:
(a) The constructor returns normally by reaching its end or a return statement, and the object exists.
Or:
(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed as an object.
EDIT 1:
But if the exception happens in the main(), ie after the MyClass object is fully instantiated, will the MyClass destructor be invoked?
Yes, it will be!
That is the purpose of using scoped_ptr, Once an exception is thrown in main, Stack Unwinding would cause all local objects to be deallocated, this means that myinst(which resides on stack) will also be deallocated, which in turn will call the destructor of MyClass.
Refer the Boost doccumentation when in doubt:
The scoped_ptr class template stores a pointer to a dynamically allocated object. (Dynamically allocated objects are allocated with the C++ new expression.) The object pointed to is guaranteed to be deleted, either on destruction of the scoped_ptr, or via an explicit reset
EDIT 2:
Why does your edited program crash?
Your program shows crashes because, You throw an exception but you never catch it. when such a scenario occurs an special function called terminate() is called whose default behavior is to call abort().It is implementation defined behavior whether stack is Unwound before terminate() is called in this particular scenarioRef 1.Seems your implementation doesn't & you should not rely on this behavior as well.
You can modify your program as follows to handle the exception and you should get the behavior you were expecting:
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
void doSomething()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
}
int main()
{
try
{
doSomething();
}
catch(int &obj)
{
std::cout<<"Exception Handled";
}
}
Ref1C++03 15.5.1 The terminate() function
In the following situations exception handling must be abandoned for less subtle error handling techniques:
....
— when the exception handling mechanism cannot find a handler for a thrown exception (15.3),
....
In such cases,
void terminate();
is called (18.6.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before terminate() is called. In all other situations, the stack shall not be unwound before terminate() is called. An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call to terminate().
Because calling the destructor doesn't make sense in this case.
You only destruct things which are constructed, yet your object never fully constructs. Your class members have been constructed, though, and will have their destructors called.
If a constructor throws exception, then the destructor of the class will not be called, because the object is not fully constructed.
See this link how to manage resources in such situation:
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10
When the exception is thrown from the constructor (beginning or half way or at the end of the call), then it's assured that the object is not constructed.
So it's well defined not to invoke the destructor of an object which was never constructed.
Here is one related FAQ from Bjarne's website.
The destructor for MyClass was never invoked because no objects of type MyClass were ever constructed. Each attempt to construct one was aborted, due to the exception being thrown.
As an aside, if you want your debug messages to display -- especially if you're dealing with the program crashing -- you really ought to flush the streams: i.e. using std::endl instead of '\n' at the end of line. (or inserting std::flush)
While merely using '\n' often works, there are enough situations where it fails and it's really, really confusing to debug if you don't make a habit of doing things right.