online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
#ifdef UNIT_TESTING #include <iostream> #include <sstream> #define SHOW_(expect, ...)\ do {\ std::ostringstream result;\ result.copyfmt(std::cout);\ result << (__VA_ARGS__);\ std::cout << __FUNCTION__ << ':' << __LINE__ << '\t'\ << #__VA_ARGS__ << " --> " << result.str();\ if (result.str() != expect) {\ std::cout << " != " << expect;\ }\ std::cout << std::endl;\ }\ while (0) #include "UpDownCounter.h" void single_counter_constructors() { SHOW_("3", UpDownCounter{3, 5, nullptr}.GetValue()); SHOW_("5", UpDownCounter{3, 5, nullptr}.GetLimit()); // SHOW_("3", UpDownCounter{3, 5, NULL}.GetValue()); // SHOW_("5", UpDownCounter{3, 5, NULL}.GetLimit()); SHOW_("3", UpDownCounter{3, 5}.GetValue()); SHOW_("5", UpDownCounter{3, 5}.GetLimit()); SHOW_("0", UpDownCounter{5, nullptr}.GetValue()); SHOW_("5", UpDownCounter{5, nullptr}.GetLimit()); // SHOW_("0", UpDownCounter{5, NULL}.GetValue()); // SHOW_("5", UpDownCounter{5, NULL}.GetLimit()); SHOW_("0", UpDownCounter{5}.GetValue()); SHOW_("5", UpDownCounter{5}.GetLimit()); SHOW_("0", UpDownCounter{}.GetValue()); SHOW_("0", UpDownCounter{}.GetLimit()); } void chained_counter_constructors() { UpDownCounter hi{0, 3}; SHOW_("0", hi.GetValue()); SHOW_("3", hi.GetLimit()); UpDownCounter lo{&hi}; SHOW_("0", lo.GetValue()); SHOW_("0", lo.GetLimit()); SHOW_("2", lo.DownCount(), hi.GetValue()); SHOW_("0", lo.UpCount(), hi.GetValue()); // !!! // TBD: Test other combinations with chained counters // !!! } #include <limits> void single_counter_setter() { UpDownCounter ud_0_max{}; SHOW_("0", ud_0_max.GetValue()); SHOW_("0", ud_0_max.GetLimit()); SHOW_("123", ud_0_max.SetValue(123), ud_0_max.GetValue()); SHOW_("0", ud_0_max.GetLimit()); } #include <string> void single_counter_max_wrap() { const auto max = std::numeric_limits<UpDownCounter::value_type>::max(); auto max_init = [](auto m) { std::ostringstream os; os << m; return os.str(); }; const auto almost_max = max_init(max-1); const auto exactly_max = max_init(max+0); UpDownCounter ud_0_max{}; SHOW_("0", ud_0_max.GetValue()); SHOW_("0", ud_0_max.GetLimit()); SHOW_(almost_max, ud_0_max.SetValue(max-1), ud_0_max.GetValue()); SHOW_(exactly_max, ud_0_max.UpCount(), ud_0_max.GetValue()); SHOW_("0", ud_0_max.UpCount(), ud_0_max.GetValue()); SHOW_("1", ud_0_max.UpCount(), ud_0_max.GetValue()); SHOW_("0", ud_0_max.DownCount(), ud_0_max.GetValue()); SHOW_(exactly_max, ud_0_max.DownCount(), ud_0_max.GetValue()); SHOW_(almost_max, ud_0_max.DownCount(), ud_0_max.GetValue()); } void single_counter_oflow() { UpDownCounter ud_3_5{3, 5}; SHOW_("3", ud_3_5.GetValue()); SHOW_("5", ud_3_5.GetLimit()); SHOW_("4", ud_3_5.UpCount(), ud_3_5.GetValue()); SHOW_("5", ud_3_5.GetLimit()); SHOW_("0", ud_3_5.UpCount(), ud_3_5.GetValue()); SHOW_("5", ud_3_5.GetLimit()); SHOW_("1", ud_3_5.UpCount(), ud_3_5.GetValue()); SHOW_("5", ud_3_5.GetLimit()); SHOW_("0", ud_3_5.DownCount(), ud_3_5.GetValue()); SHOW_("5", ud_3_5.GetLimit()); SHOW_("4", ud_3_5.DownCount(), ud_3_5.GetValue()); SHOW_("5", ud_3_5.GetLimit()); SHOW_("3", ud_3_5.DownCount(), ud_3_5.GetValue()); SHOW_("5", ud_3_5.GetLimit()); } void chained_counters_oflow() { UpDownCounter hi{3}; SHOW_("0", hi.GetValue()); SHOW_("3", hi.GetLimit()); UpDownCounter lo{4, &hi}; SHOW_("0", lo.GetValue()); SHOW_("4", hi.GetLimit()); SHOW_("1", lo.UpCount(), lo.GetValue()); SHOW_("0", hi.GetValue()); SHOW_("2", lo.UpCount(), lo.GetValue()); SHOW_("0", hi.GetValue()); SHOW_("3", lo.UpCount(), lo.GetValue()); SHOW_("0", hi.GetValue()); SHOW_("0", lo.UpCount(), lo.GetValue()); SHOW_("1", hi.GetValue()); SHOW_("1", lo.UpCount(), lo.GetValue()); SHOW_("1", hi.GetValue()); SHOW_("0", lo.DownCount(), lo.GetValue()); SHOW_("1", hi.GetValue()); SHOW_("3", lo.DownCount(), lo.GetValue()); SHOW_("0", hi.GetValue()); } void counter_tests() { single_counter_constructors(); chained_counter_constructors(); single_counter_setter(); single_counter_max_wrap(); single_counter_oflow(); chained_counters_oflow(); } #include "Clock.h" void clock_tick_tests() { Clock c{"myclock"}; SHOW_("myclock=0.00:00:00", c); SHOW_("true", c.IsFloor()); SHOW_("myclock=0.00:00:01", c.TickUp()); SHOW_("false", c.IsFloor()); SHOW_("myclock=0.00:00:02", c.TickUp()); SHOW_("myclock=0.00:00:03", c.TickUp()); SHOW_("myclock=0.00:00:58", c.Seconds(58)); SHOW_("myclock=0.00:00:59", c.TickUp()); SHOW_("myclock=0.00:01:00", c.TickUp()); SHOW_("false", c.IsFloor()); SHOW_("myclock=0.00:01:01", c.TickUp()); SHOW_("myclock=0.00:59:59", c.Minutes(59).Seconds(59)); SHOW_("myclock=0.01:00:00", c.TickUp()); SHOW_("false", c.IsFloor()); SHOW_("myclock=0.23:59:59", c.Hours(23).Minutes(59).Seconds(59)); SHOW_("myclock=1.00:00:00", c.TickUp()); SHOW_("false", c.IsFloor()); SHOW_("myclock=123.00:00:00", c.Days(123)); SHOW_("myclock=122.23:59:59", c.TickDown()); SHOW_("myclock=122.23:00:01", c.Minutes().Seconds(1)); SHOW_("myclock=122.23:00:00", c.TickDown()); SHOW_("myclock=122.22:59:59", c.TickDown()); SHOW_("myclock=122.00:00:00", c.Hours().Minutes().Seconds()); SHOW_("false", c.IsFloor()); SHOW_("myclock=0.00:00:00", c.Days()); SHOW_("true", c.IsFloor()); } int main() { std::cout.setf(std::ios::boolalpha); counter_tests(); clock_tick_tests(); } #else #include <cstdlib> #include <stdexcept> #include <iostream> extern void appl(); int main() { try { appl(); return EXIT_SUCCESS; } catch (const char* e) { std::clog << "terminated -- reason: " << e << std::endl; } return EXIT_FAILURE; } #endif
#ifndef ICLOCK_H #define ICLOCK_H #include <iosfwd> class IClock { public: virtual ~IClock() =default; virtual void Print(std::ostream&) const =0; virtual bool IsCeiling() const =0; virtual bool IsFloor() const =0; virtual IClock& TickUp() =0; virtual IClock& TickDown() =0; }; inline std::ostream& operator<<(std::ostream& lhs, const IClock& rhs) { rhs.Print(lhs); return lhs; } #endif
#ifndef CLOCK_H #define CLOCK_H #include <cstring> #include <iosfwd> #include "IClock.h" #include "UpDownCounter.h" class Clock : public IClock { const char* name_; UpDownCounter days_; UpDownCounter hours_; UpDownCounter minutes_; UpDownCounter seconds_; public: Clock(const char* name, UpDownCounter::value_type days = 0, UpDownCounter::value_type hours = 0, UpDownCounter::value_type minutes = 0, UpDownCounter::value_type seconds = 0) : name_{std::strcpy(new char[std::strlen(name)+1], name)} , days_{days, 0, nullptr} , hours_{hours, 24, &days_} , minutes_{minutes, 60, &hours_} , seconds_{seconds, 60, &minutes_} {} ~Clock() { delete[] name_; } // REQUIRED to return heap memory Clock(const Clock&) =delete; // NO copy c'tor Clock& operator=(const Clock&) =delete; // NO copy assignment Clock(Clock&&) =delete; // NO move c'tor Clock& operator=(Clock&&) =delete; // NO move assignment Clock& Days(unsigned v = 0) { days_.SetValue(v); return *this; } Clock& Hours(unsigned v = 0) { hours_.SetValue(v); return *this; } Clock& Minutes(unsigned v = 0) { minutes_.SetValue(v); return *this; } Clock& Seconds(unsigned v = 0) { seconds_.SetValue(v); return *this; } virtual void Print(std::ostream&) const override final; virtual bool IsCeiling() const override final; virtual bool IsFloor() const override final; virtual IClock& TickUp() override final { if (!IsCeiling()) seconds_.UpCount(); return *this; } virtual IClock& TickDown() override final { if (!IsFloor()) seconds_.DownCount(); return *this; } }; #endif
#include "Clock.h" #include <iostream> #include <iomanip> bool Clock::IsCeiling() const { return (seconds_.GetValue()+1 == 0) && (minutes_.GetValue()+1 == 0) && (hours_.GetValue()+1 == 0) && (days_.GetValue()+1 == 0); } bool Clock::IsFloor() const { return (seconds_.GetValue() == 0) && (minutes_.GetValue() == 0) && (hours_.GetValue() == 0) && (days_.GetValue() == 0); } void Clock::Print(std::ostream& s) const { std::ostream os{s.rdbuf()}; os.fill('0'); auto name = name_ ? name_ : "?dead?"; os << name << '=' << days_.GetValue() << '.' << std::setw(2) << hours_.GetValue() << ':' << std::setw(2) << minutes_.GetValue() << ':' << std::setw(2) << seconds_.GetValue(); }
#ifndef UP_DOWN_COUNTER_H #define UP_DOWN_COUNTER_H #include <cstdint> #include <type_traits> class UpDownCounter { public: using value_type = std::uint8_t; static_assert(std::is_integral<value_type>::value && std::is_unsigned<value_type>::value, "designed to work with unsigned integral types only"); private: value_type value_{}; const value_type max_value_{}; UpDownCounter *next_counter_{}; public: UpDownCounter() =default; UpDownCounter(const UpDownCounter&) =delete; UpDownCounter(UpDownCounter&&) =delete; UpDownCounter& operator=(const UpDownCounter&) =delete; UpDownCounter& operator=(UpDownCounter&&) =delete; UpDownCounter(value_type value, value_type max_value, UpDownCounter* next_counter) : value_{value} , max_value_{max_value} , next_counter_{next_counter} {} UpDownCounter(value_type max_value, UpDownCounter* next_counter) : UpDownCounter(0, max_value, next_counter) {} UpDownCounter(value_type value, value_type max_value) : UpDownCounter(value, max_value, nullptr) {} UpDownCounter(value_type max_value) : UpDownCounter(0, max_value, nullptr) {} UpDownCounter(UpDownCounter* next_counter) : UpDownCounter(0, 0, next_counter) {} void SetValue(value_type value) { value_ = value; } int GetValue() const { return value_; } int GetLimit() const { return max_value_; } void UpCount(); void DownCount(); }; #endif
#include "UpDownCounter.h" void UpDownCounter::UpCount() { if (++value_ == max_value_) { value_ = 0; if (next_counter_) { next_counter_->UpCount(); } } } void UpDownCounter::DownCount() { if (value_ == 0) { value_ = max_value_; if (next_counter_) { next_counter_->DownCount(); } } --value_; }
#include <iostream> void appl() { throw "not yet implemented"; }
A Clock That Can Tick Up And Down --------------------------------- At this point a "fresh start" is made by building a `Clock` which can count up and down. The former are build based on objects of `UpDownCounter`-s, which – as their name suggests – supports counting up and down too, not only when used "stand alone" but also when "chained" together. Intensive test code is supplied for both classes. (It may also be useful to understand the intended use of both of the classes.)
To advance to the next step apply the following changes: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! STOP – FIRST do an thorough code review so that you at least can answer the questions following below. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * Obviously there are two different `main` programs included in `main.cpp` – how is it selected which one gets compiled? * What is the difference between between the `SHOW` macro used until now and the `SHOW_` macro with the underscore at the end that is used here? * Understand the purpose of the different constructors of class `UpDownCounter`: * Which ones are for building chains of counters? * Which ones allow to build a counter that uses? * What may be the reason for using a `static_assert` to enforce an unsigned type for instantiating the `UpDownCounter`? * What (currently) happens if you compile `main` so that it run the code in `appl.cpp`? ----------------------------------------------------------------- If you think you have understood enough of the code to do one or more of the modifications suggested below feel free to try your hands on it. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - As all suggestions are INDEPENDANT of each other you may well READ THE WHOLE LIST FIRST and then "pick and choose" according to the "General Topic" which is of most interest to you. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Alternatively go to the solutions and compare the source files with tool of your choice shows the diff-s. ----------------------------------------------------------------- * General Topic – Code Robustness * In the constructor of class `UpDownCounter` make sure the current `value_` is inside the range `0` and `max_value - 1` (Proposal: If the value set is equal to or exceeds the maximum value allowed set it to the maximum allowed value. * Similar in `SetValue`, but in this case indicate via a `bool` return value whether the new value has actually been set (then return `true`) or was out of range and has not been set (then return `false`). * General Topic – Exceptions * Modify the `main` program` calling the `appl` function (defined in source file `appl.c`) so that it catches the exception currently thrown and displays its text before ending with `EXIT_FAILURE`. * Try throwing the following different exceptions from `appl` and demonstrate a `catch(...)` (i.e. using three dots as argument list will handle them all: * just an integral number as "error code"; * an exception class `NotYetImplememted` defined for exactly that purpose; * an appropriate class from the standard exceptions; * In the `main` program calling `appl` in its `try` block, add an add all the appropriate `catch` blocks to show a meaningful message depending on which exception was thrown, i.e. * if an integral value (as "error code") is thrown, include its value in the message; * if a `const char *` is throw simply display that; * if a standard exception is thrown display its `what()` text; * if the most generic catch block (the one defined with the three dots in its parenthesis) give a general message like "application terminated with non-standard exception" (you cannot do more than that as no information is portably available in this case); * If you throw an individually defined `NotYetImplemented` exception demonstrate what happens if there is NO specific `catch` block for it … * … when this exception is actually derived from one of standard exceptions; * … and when this is NOT the case. * General Topic – TDD (Test Driven Development) * Modify the `SHOW_`-macro so that … * … it generates output ONLY if the expectation is NOT met * … it counts in two global variables how many times it has been called and how many time the expectation was not met. * At the end of the `main` program doing all the tests show a message how tests have been run and how many of them failed – if any, otherwise you may just show "N tests passed" (with `N` being the total number of tests of course). * General Topic – "Copy vs. Move" * Consider the effort necessary to turn `Clock` from currently being neither "copyable" nor "movable" into a "move only" class (i.e. still not copyable but may be returned as result from a "factory" function. * Be sure to understand the potential problem with the `UpDownCounter` chaining via pointers – the fact these objects are NEITHER "copyable" NOR "movable" themselves has an important reason! * The solution is NOT to provide move-operations in the `UpDownCounter` class – the context to do it correctly is NOT available here! * Rather the move-operations of class `Clock` needs to use the appropriate constructors of `UpDownCounter` (which already exists) to take the `value_` and `max_value_` from the `Clock` object being MOVED FROM but build the chain in the correct for the object being MOVED TO. * Beyond that, don't forget that the `name_` (pointer member) of class `Clock` would need to be moved too. * If you feel you understood that all – GO FOR IT AND DO THE IMPLEMENTATION … * … and do not forget to ADD TESTS for it too * (or maybe write the tests before the implementation, which would be even more in the "spirit of TDD")
all: main run run: main ./main main: *.cpp *.h g++ -std=c++14 *.cpp -o $@ unit_tests: *.cpp *.h g++ -std=c++14 -DUNIT_TESTING *.cpp -o unit_tests @./unit_tests clean: -rm -f *.o a.out core main unit_tests zip: clean zip ../clock-07.zip *.txt *.cpp *.h Makefile .PHONY: all run clean zip

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue