Code sample one:
try {
exception e;
throw e;
} catch(exception& refer)
Code sample two:
exception& method()
{
exception e;
return e;
}
Some books mentioned that code sample one is ok, code two is wrong due to e in it is a local variable and will destroy when the function ends, but my question is why is sample code one okay? Isn't the e a local variable too?
Yes, in sample one, e is local to the try block, and is destroyed upon exiting that scope. But when you throw, the compiler makes a copy (or move), who's lifetime is extended to the end of the catch block, and it is this copy to which the reference refer refers.
For figuring out what the compiler does in cases like this, I always like to pull out my Noisy class.
#include <iostream>
class Noisy
{
public:
Noisy()
{ std::cout << "Noisy default construct\n"; }
Noisy(Noisy const&)
{ std::cout << "Noisy copy\n"; }
Noisy(Noisy&&)
{ std::cout << "Noisy move\n"; }
~Noisy()
{ std::cout << "Noisy destroy\n"; }
Noisy& operator=(Noisy const&)
{ std::cout << "Noisy copy assign\n"; return *this; }
Noisy& operator=(Noisy&&)
{ std::cout << "Noisy move assign\n"; return *this; }
void swap(Noisy&)
{ std::cout << "Noisy swap\n"; }
};
int main(int argc, char* argv[])
{
try
{
std::cout << "in try block\n";
Noisy n;
std::cout << "about to throw n\n";
throw n;
std::cout << "end of try block\n";
}
catch (Noisy & n)
{
std::cout << "in catch block\n";
}
std::cout << "after catch\n";
}
Related
This question is for understanding the effect of a class that's used for RAII; specifically if a variable of that class is allocated at the beginning of a function, is the destructor only called when exiting the function (by either return or throw) or can a conforming compiler call the destructor earlier? That is: in a C++ function, is it possible for the compiler to re-use space on the stack if a variable isn't used beyond a certain point, or is this strictly controlled by '{...}'?
Here's an example, with three variants of code for controlling scope/lifetime of a local variable. Is it possible for a conforming implementation to give the same output for f1(), f2(), f3(); or is the output given below guaranteed? (f1(), f2(), f3() are identical except for where local scope {...} are used.)
#include <iostream>
#include <string>
class Raii {
public:
explicit Raii(const std::string& name)
: name_(name) {
std::cout << "Construct " << name_ << std::endl;
}
~Raii() {
std::cout << "Destruct " << name_ << std::endl;
}
std::string name_;
};
void f1() {
[[maybe_unused]] Raii r1("f1-one");
std::cout << "after f1-one" << std::endl;
[[maybe_unused]] Raii r2("f1-two");
std::cout << "after f1-two" << std::endl;
}
void f2() {
{
[[maybe_unused]] Raii r1("f2-one");
}
std::cout << "after f2-one" << std::endl;
[[maybe_unused]] Raii r2("f2-two");
std::cout << "after f2-two" << std::endl;
}
void f3() {
{
[[maybe_unused]] Raii r1("f3-one");
}
std::cout << "after f3-one" << std::endl;
{
[[maybe_unused]] Raii r2("f3-two");
}
std::cout << "after f3-two" << std::endl;
}
int main() {
std::cout << "=== f1" << std::endl;
f1();
std::cout << std::endl << "=== f2" << std::endl;
f2();
std::cout << std::endl << "=== f3" << std::endl;
f3();
std::cout << "== end" << std::endl;
return 0;
}
and I get this output with both g++ and clang++:
=== f1
Construct f1-one
after f1-one
Construct f1-two
after f1-wo
Destruct f1-two
Destruct f1-one
=== f2
Construct f2-one
Destruct f2-one
after f2-one
Construct f2-two
after f2-two
Destruct f2-two
=== f3
Construct f3-one
Destruct f3-one
after f3-one
Construct f3-two
Destruct f3-two
after f3-two
== end
I am learning about exceptions from a book and try/catch and the OS should terminate the following program.
The book says, the message terminate called after throwing an instance of 'std::bad_alloc' should show up. But doesn't.
I am using Arch Linux and the program is not stopping. It runs, fills the RAM a bit linear until it doesn't (at about 90%), the processor is working a lot but no freezing and no terminating.
Is this a Windows only use case or how could I reproduce the error on a Linux/maybe Unix system?
#include <iostream>
#include <exception> //c++ exception
int main()
{
int *feld;
int loop = 1;
for(;;) //infinite loop
{
std::cout << "Loop number: " << loop << '\n';
try
{
feld = new int[10000];
loop++;
if (durchlauf == 100000) //since c++11
std::terminate();
}
catch(...)
{
std::cout << "Error, Program done.\n";
break;
}
}
return 0;
}
EDIT: I found out that my OOM killer is not working properly with swap enabled/at all. But c++ has its own termination process call
https://en.cppreference.com/w/cpp/error/terminate
It just doesn't issues an exception to print out the catch line.
Has anyone a hint to issue a catch termination?
I found the following code for you to program some terminations:
Hope that helps.
#include <iostream>
#include <stdexcept>
struct A {
int n;
A(int n = 0): n(n) { std::cout << "A(" << n << ") constructed successfully\n"; }
~A() { std::cout << "A(" << n << ") destroyed\n"; }
};
int foo()
{
throw std::runtime_error("error");
}
struct B {
A a1, a2, a3;
B() try : a1(1), a2(foo()), a3(3) {
std::cout << "B constructed successfully\n";
} catch(...) {
std::cout << "B::B() exiting with exception\n";
}
~B() { std::cout << "B destroyed\n"; }
};
struct C : A, B {
C() try {
std::cout << "C::C() completed successfully\n";
} catch(...) {
std::cout << "C::C() exiting with exception\n";
}
~C() { std::cout << "C destroyed\n"; }
};
int main () try
{
// creates the A base subobject
// creates the a1 member of B
// fails to create the a2 member of B
// unwinding destroys the a1 member of B
// unwinding destroys the A base subobject
C c;
} catch (const std::exception& e) {
std::cout << "main() failed to create C with: " << e.what();
}
Just for the sake of being helpful if someone steps into the same problem
a coded thrown exception after 100000 loops:
#include <iostream>
#include <exception> //c++ exception
int main()
{
int *feld;
int loop = 1;
for(;;) //infinite loop
{
std::cout << "Loop number: " << loop << '\n';
try
{
feld = new int[10000];
loop++;
if (loop == 1e5)
throw std::bad_alloc(); //has to be inside the try(){} scope
}
catch(...)
{
std::cout << "Error, Program done.\n";
break;
}
}
return 0;
}
I want to move data into other scope. And it seems to work... yet destructor of an object seems to crush application with runtime exception:
#include <iostream>
using namespace std;
struct A {
void * data;
A() {
data = new char[10000];
std::cout << "A()" << std::endl;
}
~A() {
if(data != nullptr) {
delete [] ((char *)data);
std::cout << "Deleted Data!" << std::endl;
}
std::cout << "~A() " << std::endl;
}
};
void aDo2(A && a) {
cout << "Do2" << endl;
}
void aDo(A && a) {
cout << "Do" << endl;
aDo2(A(a));
}
int main() {
{
A a;
{
aDo(move(a));
}
cout << "why" << endl;
}
cout << "here?" << endl;
// your code goes here
return 0;
}
How to make move into other scope to work correctly?
When you allocate memory with the new[] operator you must free it with the delete[] operator, otherwise you will get undefined behavior (which is one of the most common reason behind crashes).
Also, when you move a pointer, you should clear the old pointer as it's not done automatically and can leave you with two (or more) objects with the sae pointer.
Does destructor get called on std::map elements when std::map::clear is used?
I tried to debug for std::map<string,string> but could not see std::string destructor getting invoked. Can any one please help my understanding?
Documentation states it gets called, but I could not notice it.
Documentation is right, it does get called.
The destruction will be done by the method std::allocator<T>::deallocate(). Trace through that in your debugger.
http://www.cplusplus.com/reference/std/memory/allocator/
The destructor does get called. Here is an example to illustrate:
#include <iostream>
#include <map>
class A
{
public:
A() { std::cout << "Constructor " << this << std::endl; }
A(const A& other) { std::cout << "Copy Constructor " << this << std::endl; }
~A() { std::cout << "Destructor " << this <<std::endl; }
};
int main()
{
std::map<std::string, A> mp;
A a;
mp.insert(std::pair<std::string, A>("hello", a));
mp.clear();
std::cout << "Ending" << std::endl;
}
This will report an output similar to this:
Constructor 0xbf8ba47a
Copy Constructor 0xbf8ba484
Copy Constructor 0xbf8ba48c
Copy Constructor 0x950f034
Destructor 0xbf8ba48c
Destructor 0xbf8ba484
Destructor 0x950f034
Ending
Destructor 0xbf8ba47a
So, you can see that the destructors get called by the calling the clear function.
try with a std::map<A,B> where A and B are custom types that have a destructor in which you have set a breakpoint. You will see that it does get invoked, and exactly what scope this destruction happens at.
Here is a bit more of a complete test, building on Chris Mansley's code as I wanted to see the effect on values, ptrs and refs - and I wanted to see the difference
between clear and erase. No difference. In summary the destructor is only called
for value types, which you would expect. I just like to check my understanding 8)
#include <iostream>
#include <map>
class A
{
public:
std::string some_data;
A(std::string some_data) : some_data(some_data) {
std::cout << " A(" << some_data << ") #" << this << std::endl;
}
A(const A& other) {
some_data = other.some_data;
std::cout << " Copy A(" << other.some_data << ") #" << this << std::endl;
}
~A() {
std::cout << " Destruct ~A(" << some_data << ") #" << this << std::endl;
}
};
void clear_test_value (void)
{
std::cout << "clear_test_value() {" << std::endl;
std::map<std::string, A> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A>("key1", a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_value (void)
{
std::cout << "erase_test_value() {" << std::endl;
std::map<std::string, A> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A>("key2", a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void clear_test_ptr (void)
{
std::cout << "clear_test_ptr() {" << std::endl;
std::map<std::string, A*> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A*>("key1", &a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_ptr (void)
{
std::cout << "erase_test() {" << std::endl;
std::map<std::string, A*> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A*>("key2", &a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void clear_test_ref (void)
{
std::cout << "clear_test_ref() {" << std::endl;
std::map<std::string, A&> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A&>("key1", a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_ref (void)
{
std::cout << "erase_test_ref() {" << std::endl;
std::map<std::string, A&> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A&>("key2", a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
int main ()
{
clear_test_value();
erase_test_value();
clear_test_ptr();
erase_test_ptr();
clear_test_ref();
erase_test_ref();
return (0);
}
Output:
clear_test_value() {
A(A1 data) #0x7ffee07389a0
Copy A(A1 data) #0x7ffee0738960
Copy A(A1 data) #0x7fe98fc029c8
Destruct ~A(A1 data) #0x7ffee0738960
Destruct ~A(A1 data) #0x7fe98fc029c8
}
Destruct ~A(A1 data) #0x7ffee07389a0
erase_test_value() {
A(A1 data) #0x7ffee07387f0
Copy A(A1 data) #0x7ffee07387b0
Copy A(A1 data) #0x7fe98fc029c8
Destruct ~A(A1 data) #0x7ffee07387b0
Destruct ~A(A1 data) #0x7fe98fc029c8
}
Destruct ~A(A1 data) #0x7ffee07387f0
clear_test_ptr() {
A(A1 data) #0x7ffee07389b0
}
Destruct ~A(A1 data) #0x7ffee07389b0
erase_test() {
A(A1 data) #0x7ffee0738800
}
Destruct ~A(A1 data) #0x7ffee0738800
clear_test_ref() {
A(A1 data) #0x7ffee07389b0
}
Destruct ~A(A1 data) #0x7ffee07389b0
erase_test_ref() {
A(A1 data) #0x7ffee0738800
}
Destruct ~A(A1 data) #0x7ffee0738800
I have read several articles here and else where that it is OK to throw exception from constructor. However, I have noticed that it doesn't call destructor of base class or its data members if an exception is thrown from the constructor. Consider the following example:
#include <iostream>
using namespace std;
struct C
{
C() { cout << __FUNCTION__ << endl; }
~C() { cout << __FUNCTION__ << endl; }
};
struct E: public C
{
C c;
E() { cout << __FUNCTION__ << endl; throw 4; }
~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
E e;
}
$ g++ test.cpp; ./a.exe
C
C
E
terminate called after throwing an instance of 'int'
Aborted (core dumped)
In this case, E's constructor throws an exception but C's destructor as a data member or as a base class is not called. Now if C's destructor performs some cleanup operation like closing files/sockets and deleting heap allocations, this can cause problems.
So my question is why and when is it OK to throw exceptions from constructors.
If you catch the error, the destructor will be run. When an uncaught exception is thrown in C++, the runtime calls std::terminate. By default, std::terminate calls std::abort which specifically does not call destructors on the way out.
With this version:
#include <iostream>
using namespace std;
struct C
{
C() { cout << __FUNCTION__ << endl; }
~C() { cout << __FUNCTION__ << endl; }
};
struct E: public C
{
C c;
E() { cout << __FUNCTION__ << endl; throw 4; }
~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
try {
E e;
} catch(...) {
}
return 0;
}
I get output:
C
C
E
~C
~C
I have noticed that it doesn't call destructor of base class or its data members if an exception is thrown from the constructor
Yes, it does.
However, since you don't catch that exception in the entire program, the program is immediately terminated.
If you were to catch the exception somewhere higher up the call stack, then the destructors of base class and members would be invoked as expected.
You don't handle the "exception".
> cat test.cpp
#include <iostream>
using namespace std;
struct C
{
C() { cout << __FUNCTION__ << endl; }
~C() { cout << __FUNCTION__ << endl; }
};
struct E: public C
{
C c;
E() { cout << __FUNCTION__ << endl; throw 4; }
~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
try
{
E e;
}
catch (int i)
{
std::cerr << "Handled " << i << std::endl;
}
}
Build and run..
> make test
make: `test' is up to date.
> ./test
C
C
E
~C
~C
Handled 4
>
Both Cs destructed and a perfectly normal termination.
1) E's constructor catched the exception and ran completly.
Therefore, its object is created and the distructor is
invoked.
struct C
{
C() {cout <<__FUNCTION__<< endl;}
~C() {cout <<__FUNCTION__<< endl;}
};
struct E: public C
{
C c;
E() {
try {
cout <<__FUNCTION__<< endl;
throw 4;
}
catch(int i) {
cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
}
}
~E() {cout << __FUNCTION__ << endl;}
void print(){
cout<<"obj of class E is created"<<endl;
}
};
int main()
{
try {
E e;
e.print();
}
catch(int i) {
cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
}
return 0;
}
/*
Results:
C::C
C::C
E::E
int 4 is catched by E::E
obj of class E is created
E::~E
C::~C
C::~C
*/
2) E's constructor didn’t catch the exception and ran incompletly.
In result, its object is not created. Therefore, its distructor
is not invoked.
struct C
{
C() {cout <<__FUNCTION__<< endl;}
~C() {cout <<__FUNCTION__<< endl;}
};
struct E: public C
{
C c;
E() {
try {
cout <<__FUNCTION__<< endl;
throw 4;
}
catch(float i) {
cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
}
}
~E() {cout << __FUNCTION__ << endl;}
void print(){
cout<<"obj of class E is created"<<endl;
}
};
int main()
{
try {
E e;
e.print();
}
catch(int i) {
cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
}
return 0;
}
/*
Results:
C::C
C::C
E::E
C::~C
C::~C
int 4 catched by main function
*/