CS计算机代考程序代写 c++ COMP6771 Advanced C++ Programming

COMP6771 Advanced C++ Programming
Week 4.2 Exceptions
1

Why?
In this lecture
Sometimes our programs need to deal with unexpected runtime errors and handle them gracefully.
What?
Exception object
Throwing and catching exceptions Rethrowing
noexcept
2

Let’s start with an example
What does this produce?
1 #include
2 #include
3
4 auto main() -> int {
5 std::cout << "Enter -1 to quit\n"; 6 std::vector items{97, 84, 72, 65};
7 std::cout << "Enter an index: "; 8 for (int print_index; std::cin >> print_index; ) {
9 if (print_index == -1) break;
10 std::cout << items.at(print_index) << '\n'; 11 std::cout << "Enter an index: "; 12 } 13 } demo455-exception1.cpp 3.1 Let's start with an example What does this produce? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include
#include
auto main() -> int {
std::cout << "Enter -1 to quit\n"; std::vector items{97, 84, 72, 65};
std::cout << "Enter an index: "; for (int print_index; std::cin >> print_index; ) {
if (print_index == -1) break;
try {
std::cout << items.at(print_index) << '\n'; items.resize(items.size() + 10); } catch (const std::out_of_range& e) { std::cout << "Index out of bounds\n"; } catch (...) { std::cout << "Something else happened"; } std::cout << "Enter an index: "; } } demo455-exception2.cpp 3.2 Exceptions: What & Why? What: Exceptions: Are for exceptional circumstances Happen during run-time anomalies (things not going to plan A!) Exception handling: Run-time mechanism C++ detects a run-time error and raises an appropriate exception Another unrelated part of code catches the exception, handles it, and potentially rethrows it Why: Allows us to gracefully and programmatically deal with anomalies, as opposed to our program crashing. 4 What are "Exception Objects"? Any type we derive from std::exception throw std::out_of_range("Exception!"); throw std::bad_alloc("Exception!"); Why std::exception? Why classes? #include for std::exception object
#include for objects that inherit std::exception
https://en.cppreference.com/w/cpp/error/exception https://stackoverflow.com/questions/25163105/stdexcept-vs-exception-headers-in-c
5

Conceptual Structure
Exceptions are treated like lvalues
Limited type conversions exist (pay attention to them):
nonconst to const
other conversions we will not cover in the course
1
2
3
4
5
6 7}
try {
// Code that may throw an exception
} catch (/* exception type */) {
// Do something with the exception
} catch (…) { // any exception
// Do something with the exception
https://en.cppreference.com/w/cpp/language/try_catch
6.1

Multiple catch options
This does not mean multiple catches will happen, but rather that multiple options are possible for a single catch
1 #include
2 #include
3
4 auto main() -> int {
5 auto items = std::vector{};
6 try{
7 items.resize(items.max_size() + 1);
8 } catch (std::bad_alloc& e) {
9 std::cout << "Out of bounds.\n"; 10 } catch (std::exception&) { 11 std::cout << "General exception.\n"; 12 } 13 } 6.2 Catching the right way Throw by value, catch by const reference Ways to catch exceptions: By value (no!) By pointer (no!) By reference (yes) References are preferred because: more efficient, less copying (exploring today) no slicing problem (related to polymorphism, exploring later) (Extra reading for those interested) https://blog.knatten.org/2010/04/02/always-catch-exceptions- by-reference/ 7.1 Catch by value is inefficient 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include
class Giraffe {
public:
Giraffe() { std::cout << "Giraffe constructed" << '\n'; } Giraffe(const Giraffe &g) { std::cout << "Giraffe copy-constructed" << '\n'; } ~Giraffe() { std::cout << "Giraffe destructed" << '\n'; } }; void zebra() { throw Giraffe{}; } void llama() { try{ zebra(); catch (Giraffe g) { std::cout << "caught in llama; rethrow" << '\n'; throw; } } } int try{ main() { llama(); catch (Giraffe g) { std::cout << "caught in main" << '\n'; } } } demo456-by-value.cpp 7.2 Catch by value inefficiency 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include
class Giraffe {
public:
Giraffe() { std::cout << "Giraffe constructed" << '\n'; } Giraffe(const Giraffe &g) { std::cout << "Giraffe copy-constructed" << '\n'; } ~Giraffe() { std::cout << "Giraffe destructed" << '\n'; } }; void zebra() { throw Giraffe{}; } void llama() { try{ zebra(); catch (const Giraffe& g) { std::cout << "caught in llama; rethrow" << '\n'; throw; } } } int try{ main() { llama(); catch (const Giraffe& g) { std::cout << "caught in main" << '\n'; } } } demo457-by-ref.cpp 7.3 Rethrow When an exception is caught, by default the catch will be the only part of the code to use/action the exception What if other catches (lower in the precedence order) want to do something with the thrown exception? 9 10 11 12 13 14 15 } catch (T& e2) { std::cout << "Caught too!\n"; throw; } } catch (...) { std::cout << "Caught too!!\n"; } 1 2 3 4 5 6 7 8} try { try{ try { throw T{}; } catch (T& e1) { std::cout << "Caught\n"; throw; 8.1 (Not-advisable) Rethrow, catch by value 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include
class Cake {
public:
Cake() : pieces_{8} {}
int getPieces() { return pieces_; }
Cake& operator–() { –pieces_; return *this; }
private:
int pieces_;
};
int main() { try{
try { try {
}
}
catch (Cake e2) {
–e2;
std::cout << "e2 Pieces: " << e2.getPieces() << " addr: " << &e2 << "\n"; throw; } throw Cake{}; catch (Cake& e1) { --e1; std::cout << "e1 Pieces: " << e1.getPieces() << " addr: " << &e1 << "\n"; throw; } } catch (Cake& e3) { --e3; std::cout << "e3 Pieces: " << e3.getPieces() << " addr: " << &e3 << "\n"; } } demo458-rethrow.cpp 8.2 Exception safety levels This part is not specific to C++ Operations performed have various levels of safety No-throw (failure transparency) Strong exception safety (commit-or-rollback) Weak exception safety (no-leak) No exception safety 9.1 No-throw guarantee Also known as failure transparency Operations are guaranteed to succeed, even in exceptional circumstances Exceptions may occur, but are handled internally No exceptions are visible to the client This is the same, for all intents and purposes, as noexcept in C++ Examples: Closing a file Freeing memory Anything done in constructors or moves (usually) Creating a trivial object on the stack (made up of only ints) 9.2 Strong exception safety Also known as "commit or rollback" semantics Operations can fail, but failed operations are guaranteed to have no visible effects Probably the most common level of exception safety for types in C++ All your copy-constructors should generally follow these semantics Similar for copy-assignment Copy-and-swap idiom (usually) follows these semantics (why?) Can be difficult when manually writing copy-assignment 9.3 Strong exception safety To achieve strong exception safety, you need to: First perform any operations that may throw, but don't do anything irreversible Then perform any operations that are irreversible, but don't throw 9.4 Basic exception safety This is known as the no-leak guarantee Partial execution of failed operations can cause side effects, but: All invariants must be preserved No resources are leaked Any stored data will contain valid values, even if it was different now from before the exception Does this sound familiar? A "valid, but unspecified state" Move constructors that are not noexcept follow these semantics 9.5 No exception safety No guarantees Don't write C++ with no exception safety Very hard to debug when things go wrong Very easy to fix - wrap your resources and attach lifetimes This gives you basic exception safety for free 9.6 noexcept specifier Specifies whether a function could potentially throw It doesn't not actually prevent a function from throwing an exception https://en.cppreference.com/w/cpp/language/noexcept_spec STL functions can operate more efficiently on noexcept functions 1 class S { 2 public: 3 int foo() const; // may throw 4} 5 6 class S { 7 public: 8 int foo() const noexcept; // does not throw 9} 10 CHECK_NOTHROW(expr); CHECK_THROWS(expr); Testing exceptions CHECK_THROWS_AS(expr, type); Checks expr doesn't throw an exception. Checks expr throws an exception. Checks expr throws type (or somthing derived from type). REQUIRES_THROWS* also available. 11 . 1 Testing exceptions namespace Matchers = Catch::Matchers; CHECK_THROWS_WITH( expr, Matchers::Message("message")); CHECK_THROWS_MATCHES( expr, type, Matchers::Message("message")); Checks expr throws an exception with a message. CHECK_THROWS_AS and CHECK_THROWS_WITH in a single check. REQUIRES_THROWS* also available. 11 . 2