What happens to the call stack when an exception is thrown?
All activation records between where an exception is thrown and where it is caught are destroyed.
void *foo = (void*) 3;There are various types of type casting in C++ such as:
- static_cast
- dynamic_cast
- reinterpret_cast
- const_cast
We're interested in dynamic_cast.
class Foo {};
class Bar : public Foo {};
Foo *foo = new Bar;
Bar bar = (Bar) *foo;This code above will work because foo of type Bar.
class Foo {};
class Bar : public Foo {};
Foo *foo = new Foo;
Bar bar = (Bar) *foo;This code above will not work because foo is of typeFoo which may be missing members of the Bar class.
This will not get caught by the compiler. It will produce a runtime exception.
void do_something_bad() {
	std::unique_ptr<Base> b=std::make_unique<Base>();
	Derived& rd = dynamic_cast<Derived&>(*b);
}
void func2(){
	do_something_bad();
	std::cout << "In func2" << std::endl;
}
void func1() {
	func2();
	std::cout << "In func1" << std::endl;
}
int main() {
	try {
		func1();
		std::cout << "Success!" << std::endl;
	} catch (std::exception &e) {
		std::cout << "Exception! " << e.what() << std::endl;
	}
	return 0;
}What does this code print?
Answer:
Exception! std::bad castLong jumps allow you to jump between functions in your call stack. (It gives you the ability to do a GOTO in your code.)
Let's simulate our try-catch code from above using long jump.
#include <csetjmp>
#include <memory>
std::jmp_buf jump_buffer;
void do_something_weird(){
	std::cout << "About to longjmp" << std::endl;
	std::longjmp(jump_buffer, 1);
}
void func2() {
	do_something_weird();
	std::cout << "In func2" << std::endl;
}
void func1() {
	func2();
	std::cout << "In func1" << std::endl;
}
int main() {
	if(setjmp(jump_buffer) == 0) {
		std::cout << "About to call func1" << std::endl;
		func1();
	} else {
		std::cout << "Returned from longjmp" << std::endl;
	}
	return 0;
}What do setjmp and longjmp do? What does jmp_buf store?
jmp_buf stores:
- old instruction pointer
- old stack pointer
setjmp stores the address of the current function call in the jump buffer and returns twice. The first time it is called it will return 0.
When you call longjmp the second parameter will be the second return value of setjmp.
So in the above code, setjmp returns 0 first and returns 1 after long jump returns the code back to the top of main.
When an exception is thrown, what happens to the local variables on the call stack?
void func2(){
	Unwinding u("func2");
	do_something_bad();
	std::cout << "In func2"	 << std::endl;
}In this code the Unwinding destructor get called when either func2 returns or an exception gets thrown.
C++ destructors get called when an exception is thrown. How?
Well what is inside an activation record?
- Parameters of called function
- Return address
- Base pointer of calling function
- Local variables
So when an exception is called we can look at our activation record. We can destruct the current local variables then move on to the function that is located at our record's return address and repeat!
When an exception is thrown, what happens to variables on the heap?
This is results in a memory leak, unless a smart pointer is being used.
not is a higher-order predicate that takes a predicate as a parameter and returns the negation of the predicate (kinda). Be careful using not because it's a little weird.
someTree(X) :-
	X = t("t1", 
		t("t2a",
			t("t3a", nil, nil),
			t("t3b", nil, nil))),
		t("t2b",
			t("t3c", nil, nil),
			t("t3d", nil, nil)).
firstItem(t(V,_,_), V).countSpatial(0, []).
countSpatial(N, [N|Tail]) :-
  N>0,
  N2 is N-1,
  countSpatial(N2, Tail).countSpatial returns a list of values from N to 1 as one value.
countTemporal(N,N) :- N>0.
countTemporal(N,X) :-
  N>0,
  N2 is N-1,
  countTemporal(N2, X).countTemporal returns the values from N to 1 one at a time.
- Spatial means returning a values as one result
- Temporal means returning values one at a time (because the word temporal means 'relating to time')
If we want to get a spatial result from a temporal predicate we can use findall.
?- finall(X, countTemporal(50,X), Z).
If we want to get a temporal result from a spacial predicate we can use member.
?- countSpatial(50,X), member(Y, X).
Let's try making the member predicate by ourselves.
ismember(H, [H|_]).
ismember(H, [_|T]) :- ismember(H,T).The problem with ismember is that if a list has two occurrences of the value we're looking for then it will return true twice.
We want it to only return true once so we use ! which stops backtracking.
ismember(H, [H|_]) :- !.
ismember(H, [_|T]) :- ismember(H,T).