<aside> đź’ˇ Exception Safety
<aside> 💡 Specifically, 3 levels of exn safety for a f’n f:
class A {...};
class B {...};
class C {
A a;
B b;
public:
void f() {
a.g(); // may throw (strong guarantee)
b.h(); // may throw (strong guarantee)
}
}
Is C::f exn safe?
thus: no, probably not exn safe
If A::a and B::h do not have non-local side effects, can use copy + swap:
class C {
...
void f() {
A atemp = a;
B btemp = b;
atemp.g();
btemp.h();
// ↑ If those throw, original a + b still intact(無傷)
a = atemp;
b = btemp;
// ↑ But what if copy assignment throw?
// In particular what if a a=atemp succeed, but b=btemp fails?
}
};
Better if swap was no throw.
Recall: copying ptrs can’t throw
struct CImpl {
A a;
B b;
};
class C {
unique.ptr<CImpl> pImpl;
void f() {
auto tmp = make.unique<CImpl>(* pImpl);
temp->a.g();
temp->b.h();
std::swap(pImpl, tmp); // no-throw
}
};
// If either A::g or B::b offer no exn safety guarantee,
// then neither can f
<aside> đź’ˇ Exception Safety of STL - vector
vectors
void f() {
vector<c> v;
...
}
// v goes out of scope, array is freed,
// C's dtor runs for all objects in v
But…
void g() {
vector<c*> v;
...
// array is freed, ptrs don't have dtors,
// and objs ptd to by the ptrs are NOT deleted
// no explicit deallocation
}
</aside>
<aside> đź’ˇ vector<c> - owns the objs
vector<c*> - does not own the objs
vector<unique.ptr<c>> - owns the objs
vector<T>::emplace.back - offers the strong guarantee
If the move ctor offer the nothrow guarantee, emplace_back will use the move ctor. Otherwise, it will use the copy ctor, which may be slower
class C {
public:
C(C &&other) noexcept {...}
C &operator=(C &&other) noexcept {...}
};
If you know a f’n will never throw or propagate an exn, declare if noexcept. Facilitates optimization At minimam: moves & swaps should be noexcept
<aside> đź’ˇ Casting
In C
Node n;
int *ip = (int *) &n; // const-forces C++ to treat a Node* as an int*
<aside> đź’ˇ If you must const, use a C++ - style cast:
Static.cast - “sensible casts” - casts with a well-defined semantics eg. double -> int
double d;
void f(int x);
void f(double d);
f(static_cast<int>(d)); // calls void f(int x);
eg. superclass ptr → subclass ptr
Book *b = new Text {...};
Text *t = static.cast<Text*>(b);
</aside>
</aside>