C++ Library Extensions 2022.12.09
To help learn modern C++ programming
006-debug_exception.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2#include <thread>
3#include <exception>
4
5#ifdef __FUNCSIG__
6 #define Ugly_Function_Name __FUNCSIG__
7#else
8 #define Ugly_Function_Name __PRETTY_FUNCTION__
9#endif
10
11/*
12 We are going to extend C++ standard class using inheritance.
13 When we extend our class using inheritance, we should especially careful of "slicing problem."
14
15 For less experience C++ programmers, this "slicing problem" is one of the major cause of resource leak.
16
17 If the base class does not have virtual destructor,
18 We should NOT add data field to our custom class, otherwise we cannot avoid memory leak.
19
20 Only when the base class has virtual destructor,
21 we can safely add data field to our derived class.
22*/
23
25{
27
28 stream <<"Has std::exception virtual destructor ? "
29 << std::has_virtual_destructor_v< std::exception > << tpf::endl;
30
31 stream << "Has std::vector<int> virtual destructor ? "
32 << std::has_virtual_destructor_v< std::vector<int> > << tpf::endl;
33}
34
35/*
36 Since std::exception has a virtual destructor, we can safely add
37 data fields to the derived class.
38 In case of std::vector, it does not have a virtual destructor,
39 so when we add data fields to the derived class from std::vector,
40 we have to extra careful about memory leaks due to "slicing problem."
41 This slicing problem occurs only when we dynamically allocate.
42*/
43
44class exception_debug: public std::exception
45{
46 private:
47 std::string m_message;
48 int m_lineno;
49 std::string m_function_name;
50 std::string m_file_name;
51 std::string m_what_msg;
52
53 public:
54 exception_debug(std::string message = "",
55 int lineno = 0, std::string function_name ="",
56 std::string file_name = ""):
57 m_message{message}, m_lineno{lineno},
58 m_function_name{function_name}, m_file_name{file_name}
59 {
60 std::ostringstream os;
61
62 os << "exception_debug - file [" << this->m_file_name << "] \n";
63 os << "thread id [" << std::this_thread::get_id() << "] - ";
64 os << "line number [" << this->m_lineno << "] - ";
65 os << "function [" << this->m_function_name << "]\n";
66 os << "message: " << this->m_message;
67
68 this->m_what_msg = os.str();
69 }
70
71 // this is C++98 Standard, but C++11 Standard has changed.
72 virtual const char* what() const noexcept override
73 {
74 // we can return const char*, because this->m_what_msg outlives
75 // this function block scope
76 return this->m_what_msg.c_str();
77 }
78};
79
80// do not put semi colon in macro definition
81#define UglyNamed_ThrowException(message) throw exception_debug(message, __LINE__, Ugly_Function_Name, __FILE__)
82
83int division( int a, int b)
84{
85 if(b == 0)
86 {
87 UglyNamed_ThrowException("b is zero");
88 }
89
90 return a / b;
91}
92
94{
95 try
96 {
97 division(5, 0);
99
100 stream <<"Operation successful"<<tpf::endl;
101 }
102 catch(std::exception& e)
103 {
105 stream << e << tpf::endl;
106 }
107}
108int main()
109{
110 // test_virtual_destructor();
112}
#define UglyNamed_ThrowException(message)
void test_virtual_destructor()
int division(int a, int b)
int main()
void example_for_throw_debug_exception()
tpf::sstream stream
virtual const char * what() const noexcept override
exception_debug(std::string message="", int lineno=0, std::string function_name="", std::string file_name="")
constexpr auto endl
Definition: tpf_output.hpp:973
Stream output operators << are implemented.