Commit ff9239d4 authored by Marco Bubke's avatar Marco Bubke

Add exceptions seminar

parent a3479233
......@@ -2,4 +2,5 @@ TEMPLATE = subdirs
SUBDIRS = \
polymorphism \
sorting
sorting \
exceptions
#include <googletest.h>
#include <type_traits>
#include <string>
#include <stdexcept>
#include <iostream>
TEST(Exceptions, DefaultDefaultConstructor)
{
struct X
{
X() = default;
};
ASSERT_TRUE(std::is_nothrow_default_constructible<X>::value);
}
TEST(Exceptions, CustomDefaultConstructor)
{
struct X
{
X();
};
ASSERT_FALSE(std::is_nothrow_default_constructible<X>::value);
}
TEST(Exceptions, DefaultCopyConstructor)
{
struct X
{
X(const X&) = default;
};
ASSERT_TRUE(std::is_nothrow_copy_constructible<X>::value);
}
TEST(Exceptions, CustomCopyConstructor)
{
struct X
{
X(const X&);
};
ASSERT_FALSE(std::is_nothrow_copy_constructible<X>::value);
}
TEST(Exceptions, DefaultCopyOperator)
{
struct X
{
X& operator=(const X&) = default;
};
ASSERT_TRUE(std::is_nothrow_copy_assignable<X>::value);
}
TEST(Exceptions, CustomCopyOperator)
{
struct X
{
X& operator=(const X&);
};
ASSERT_FALSE(std::is_nothrow_copy_assignable<X>::value);
}
TEST(Exceptions, DefaultMoveConstructor)
{
struct X
{
X(X&&) = default;
};
ASSERT_TRUE(std::is_nothrow_move_constructible<X>::value);
}
TEST(Exceptions, CustomMoveConstructor)
{
struct X
{
X(X&&);
};
ASSERT_FALSE(std::is_nothrow_move_constructible<X>::value);
}
TEST(Exceptions, DefaultMoveOperator)
{
struct X
{
X& operator=(X&&) = default;
};
ASSERT_TRUE(std::is_nothrow_move_assignable<X>::value);
}
TEST(Exceptions, CustomMoveOperator)
{
struct X
{
X& operator=(X&&);
};
ASSERT_FALSE(std::is_nothrow_move_assignable<X>::value);
}
TEST(Exceptions, DefaultDestructorConstructor)
{
struct X
{
~X() = default;
};
ASSERT_TRUE(std::is_nothrow_destructible<X>::value);
}
TEST(Exceptions, CustomDestrcutorConstructor)
{
struct X
{
~X();
};
ASSERT_TRUE(std::is_nothrow_default_constructible<X>::value);
}
TEST(Exceptions, DefaultInheritedConstructorWithBaseDefefaultConstructor)
{
struct Base {
Base() = default;
};
struct X : public Base
{
X() = default;
};
ASSERT_TRUE(std::is_nothrow_default_constructible<X>::value);
}
TEST(Exceptions, DefaultInheritedConstructorWithBaseCustomConstructor)
{
struct Base {
Base();
};
struct X : public Base
{
X();
};
ASSERT_FALSE(std::is_nothrow_default_constructible<X>::value);
}
TEST(Exceptions, DefaultInheritedMoveConstructorWithBaseDefefaultConstructor)
{
struct Base {
Base(Base&&);
};
struct X
{
X(X&&);
};
ASSERT_FALSE(std::is_nothrow_move_constructible<X>::value);
}
TEST(Exceptions, ExplicitSetToBaseInheritedMoveConstructorWithBaseCustomConstructor)
{
struct Base {
Base(Base&&);
};
struct X : public Base
{
X(X&& x) noexcept(noexcept(Base(std::move(x))));
};
ASSERT_FALSE(std::is_nothrow_move_constructible<X>::value);
}
TEST(Exceptions, ExplicitSetToTrueInheritedMoveConstructorWithBaseCustomConstructor)
{
struct Base {
Base(Base&&);
};
struct X : public Base
{
X(X&&) noexcept(true);
};
ASSERT_TRUE(std::is_nothrow_move_constructible<X>::value);
}
TEST(Exceptions, ThrowingDestructor)
{
struct X
{
~X() noexcept(false);
};
ASSERT_FALSE(std::is_nothrow_destructible<X>::value);
}
TEST(Exceptions, ThrowingDestructorInherited)
{
struct Base {
~Base() noexcept(false);
};
struct X : public Base
{
~X() = default;
};
ASSERT_FALSE(std::is_nothrow_destructible<X>::value);
}
TEST(Exceptions, DefaultFunctionIsThrowing)
{
void function();
ASSERT_FALSE(noexcept(function()));
}
TEST(Exceptions, NoexceptFunctionIsNotThrowing)
{
void noexceptFunction() noexcept;
ASSERT_TRUE(noexcept(noexceptFunction()));
}
void inlineFunction() {};
TEST(Exceptions, InlineFunctionIsThrowing)
{
ASSERT_FALSE(noexcept(inlineFunction()));
}
TEST(Exceptions, DeallocationFunctionIsNotThrowing)
{
struct X
{
};
X *x = new X;
ASSERT_TRUE(noexcept(delete x));
}
TEST(Exceptions, MoveIfNotThrowing)
{
struct X
{
X() = default;
X(const X&) {}
X(X&&) = default; // not throwing
};
X x;
ASSERT_TRUE(std::is_rvalue_reference<decltype(std::move_if_noexcept(x))>::value);
}
TEST(Exceptions, DontMoveIfThrowing)
{
struct X
{
X() = default;
X(const X&) {}
X(X&&) {} // throwing
};
X x;
ASSERT_FALSE(std::is_rvalue_reference<decltype(std::move_if_noexcept(x))>::value);
}
TEST(Exceptions, MoveIfThrowingButThereIsNoExplicitCopyConstructor)
{
struct X
{
X() = default;
X(X&&) {} // Rule of five !!!
};
X x;
ASSERT_TRUE(std::is_rvalue_reference<decltype(std::move_if_noexcept(x))>::value);
}
template <typename Value>
struct ExampleNoexceptMove
{
Value take() noexcept(std::is_nothrow_move_assignable<Value>::value)
{
return std::move_if_noexcept(v);
}
Value v;
};
struct ExampleThrowing
{
ExampleThrowing() noexcept
{
throw 1; // completely defined: calls std::terminate
// std::set_terminate can install a handler for it
}
};
struct Statement
{
void reset();
void resetNoexcept() noexcept;
};
struct Resetter
{
Resetter(Statement &statement)
: statement(statement)
{}
~Resetter() noexcept(false) // it is dangerous because if you throw a second time maybe the destructors of your members are not called
{
if (std::uncaught_exceptions() == 0)
statement.reset();
else
statement.resetNoexcept();
}
Statement &statement; // secure because no member destructor is called
};
struct Statement2
{
void reset();
};
struct Resetter2
{
Resetter2(Statement2&statement)
: statement(statement)
{}
~Resetter2() noexcept(false)
{
try {
statement.reset();
} catch (...) {
if (std::uncaught_exceptions() == 0)
throw;
}
}
Statement2 &statement;
};
struct Value
{
};
Value createValue(); // can throw
struct ExampleCatchExceptionInConstructor
{
ExampleCatchExceptionInConstructor()
try : value(createValue())
{
} catch (...) {
// just do something about here
}
Value value;
};
void function()
try {
// can be used instead of catching a exception inside of a function body
} catch (...) {
// just do something about here
}
void exception_pointer()
{
std::exception_ptr exceptionPointer; // very useful for exception between threads
// std::future is using it
// ...
try {
// throw an exception
} catch(...) {
exceptionPointer = std::current_exception(); // capture
}
// ...
if (exceptionPointer)
std::rethrow_exception(exceptionPointer);
}
void print_exception(const std::exception& exception)
{
std::cerr << "exception: " << exception.what() << '\n';
try {
std::rethrow_if_nested(exception);
} catch(const std::exception& e) {
print_exception(e);
} catch(...) {}
}
void openFile(const std::string& path)
{
throw std::runtime_error("cannot open file");
}
void run()
{
try {
openFile("nonexistent.file");
} catch(...) {
std::throw_with_nested( std::runtime_error("run() failed") );
}
}
void baseFunction()
{
try {
run();
} catch(const std::exception& e) {
print_exception(e);
}
}
// exception: run() failed
// exception: cannot open file
include(../shared/test.pri)
TARGET = exceptions
SOURCES += \
exceptions-test.cpp
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment