blok finally v C++
authorFrantišek Kučera <franta-hg@frantovo.cz>
Wed, 30 Oct 2024 02:44:44 +0100
changeset 0e4f2d6d0e869
child 1 4502b1c7346d
blok finally v C++
Makefile
bad.cpp
good-class-generic.cpp
good-class.cpp
good-finally.cpp
good-smart-pointer.cpp
good-vector.cpp
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Wed Oct 30 02:44:44 2024 +0100
     1.3 @@ -0,0 +1,28 @@
     1.4 +CXX ?= g++
     1.5 +CXXFLAGS ?= -O2 -g3 -ggdb -Wall -Wno-sign-compare
     1.6 +CXXFLAGS += --std=c++20
     1.7 +CXXFLAGS += -fsanitize=undefined -fsanitize=address
     1.8 +LDFLAGS ?=
     1.9 +
    1.10 +SRC = $(shell find -maxdepth 1 -name '*.cpp')
    1.11 +BIN = $(shell find -maxdepth 1 -name '*.cpp' | xargs basename -s .cpp)
    1.12 +
    1.13 +all: $(BIN)
    1.14 +
    1.15 +.PHONY: all run clean
    1.16 +
    1.17 +clean:
    1.18 +	$(RM) $(BIN)
    1.19 +
    1.20 +run: $(BIN)
    1.21 +	@echo "\e[1;32mHappy path without exceptions:\e[0m"
    1.22 +	@for bin in $(BIN); do ./$$bin     ; done
    1.23 +	@echo; echo
    1.24 +	@echo "\e[1;32mInterrupted by exceptions:\e[0m"
    1.25 +	@for bin in $(BIN); do ./$$bin fail; done
    1.26 +
    1.27 +$(BIN): $(SRC)
    1.28 +	$(CXX) $(CXXFLAGS) -o $(@) $(@).cpp $(LDFLAGS)
    1.29 +
    1.30 +# Blok finally při odchytávání výjimek: C++ vs. Java
    1.31 +# https://blog.frantovo.cz/c/395/
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/bad.cpp	Wed Oct 30 02:44:44 2024 +0100
     2.3 @@ -0,0 +1,26 @@
     2.4 +#include <iostream>
     2.5 +#include <exception>
     2.6 +
     2.7 +void fxThrowing(bool fail, void* data) {
     2.8 +	std::cout << "  doing something with data " << data << std::endl;
     2.9 +	if (fail) throw std::logic_error("error from fxThrowing()");
    2.10 +}
    2.11 +
    2.12 +void fxAllocating(bool fail) {
    2.13 +	void* data = malloc(486);
    2.14 +	std::cout << "  allocated memory at: " << data << std::endl;
    2.15 +	fxThrowing(fail, data);
    2.16 +	free(data);
    2.17 +	std::cout << "  freed memory at: " << data << std::endl;
    2.18 +}
    2.19 +
    2.20 +int main(int argc, char** argv) {
    2.21 +	bool fail = argc == 2 && std::string("fail") == argv[1];
    2.22 +	const char* name = "bad";
    2.23 +	std::cout << name << " (fail=" << fail << ")\n";
    2.24 +	try {
    2.25 +		fxAllocating(fail);
    2.26 +	} catch (const std::exception& e) {
    2.27 +		std::cout << "  caught exception: " << e.what() << std::endl;
    2.28 +	}
    2.29 +}
    2.30 \ No newline at end of file
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/good-class-generic.cpp	Wed Oct 30 02:44:44 2024 +0100
     3.3 @@ -0,0 +1,42 @@
     3.4 +#include <iostream>
     3.5 +#include <exception>
     3.6 +
     3.7 +template<typename T>
     3.8 +class Resource {
     3.9 +private:
    3.10 +	Resource(const Resource&) = delete;
    3.11 +	Resource& operator=(const Resource&) = delete;
    3.12 +public:
    3.13 +	T* data;
    3.14 +	void(*dtor)(T*);
    3.15 +
    3.16 +	Resource(T* data, void(*dtor)(T*)) : data(data), dtor(dtor) {
    3.17 +		std::cout << "  created resource for data at: " << data << std::endl;
    3.18 +	}
    3.19 +
    3.20 +	virtual ~Resource() {
    3.21 +		dtor(data);
    3.22 +		std::cout << "  called destructor on: " << data << std::endl;
    3.23 +	}
    3.24 +};
    3.25 +
    3.26 +void fxThrowing(bool fail, void* data) {
    3.27 +	std::cout << "  doing something with data " << data << std::endl;
    3.28 +	if (fail) throw std::logic_error("error from fxThrowing()");
    3.29 +}
    3.30 +
    3.31 +void fxAllocating(bool fail) {
    3.32 +	Resource buf(malloc(486), free);
    3.33 +	fxThrowing(fail, buf.data);
    3.34 +}
    3.35 +
    3.36 +int main(int argc, char** argv) {
    3.37 +	bool fail = argc == 2 && std::string("fail") == argv[1];
    3.38 +	const char* name = "good-class-generic";
    3.39 +	std::cout << name << " (fail=" << fail << ")\n";
    3.40 +	try {
    3.41 +		fxAllocating(fail);
    3.42 +	} catch (const std::exception& e) {
    3.43 +		std::cout << "  caught exception: " << e.what() << std::endl;
    3.44 +	}
    3.45 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/good-class.cpp	Wed Oct 30 02:44:44 2024 +0100
     4.3 @@ -0,0 +1,41 @@
     4.4 +#include <iostream>
     4.5 +#include <exception>
     4.6 +
     4.7 +class Buffer {
     4.8 +private:
     4.9 +	Buffer(const Buffer&) = delete;
    4.10 +	Buffer& operator=(const Buffer&) = delete;
    4.11 +public:
    4.12 +	size_t size;
    4.13 +	void* data;
    4.14 +
    4.15 +	Buffer(size_t size) : size(size), data(malloc(size)) {
    4.16 +		std::cout << "  allocated memory at: " << data << std::endl;
    4.17 +	}
    4.18 +
    4.19 +	virtual ~Buffer() {
    4.20 +		free(data);
    4.21 +		std::cout << "  freed memory at: " << data << std::endl;
    4.22 +	}
    4.23 +};
    4.24 +
    4.25 +void fxThrowing(bool fail, void* data) {
    4.26 +	std::cout << "  doing something with data " << data << std::endl;
    4.27 +	if (fail) throw std::logic_error("error from fxThrowing()");
    4.28 +}
    4.29 +
    4.30 +void fxAllocating(bool fail) {
    4.31 +	Buffer buf(486);
    4.32 +	fxThrowing(fail, buf.data);
    4.33 +}
    4.34 +
    4.35 +int main(int argc, char** argv) {
    4.36 +	bool fail = argc == 2 && std::string("fail") == argv[1];
    4.37 +	const char* name = "good-class";
    4.38 +	std::cout << name << " (fail=" << fail << ")\n";
    4.39 +	try {
    4.40 +		fxAllocating(fail);
    4.41 +	} catch (const std::exception& e) {
    4.42 +		std::cout << "  caught exception: " << e.what() << std::endl;
    4.43 +	}
    4.44 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/good-finally.cpp	Wed Oct 30 02:44:44 2024 +0100
     5.3 @@ -0,0 +1,36 @@
     5.4 +#include <iostream>
     5.5 +#include <exception>
     5.6 +
     5.7 +void fxThrowing(bool fail, void* data) {
     5.8 +	std::cout << "  doing something with data " << data << std::endl;
     5.9 +	if (fail) throw std::logic_error("error from fxThrowing()");
    5.10 +}
    5.11 +
    5.12 +void fxAllocating(bool fail) {
    5.13 +	void* data = malloc(486);
    5.14 +	std::cout << "  allocated memory at: " << data << std::endl;
    5.15 +
    5.16 +	std::exception_ptr e;
    5.17 +	try {
    5.18 +		fxThrowing(fail, data);
    5.19 +	} catch (...) {
    5.20 +		e = std::current_exception();
    5.21 +	}
    5.22 +
    5.23 +	// finally:
    5.24 +	free(data);
    5.25 +	std::cout << "  freed memory at: " << data << std::endl;
    5.26 +
    5.27 +	if (e) std::rethrow_exception(e);
    5.28 +}
    5.29 +
    5.30 +int main(int argc, char** argv) {
    5.31 +	bool fail = argc == 2 && std::string("fail") == argv[1];
    5.32 +	const char* name = "good-finally";
    5.33 +	std::cout << name << " (fail=" << fail << ")\n";
    5.34 +	try {
    5.35 +		fxAllocating(fail);
    5.36 +	} catch (const std::exception& e) {
    5.37 +		std::cout << "  caught exception: " << e.what() << std::endl;
    5.38 +	}
    5.39 +}
    5.40 \ No newline at end of file
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/good-smart-pointer.cpp	Wed Oct 30 02:44:44 2024 +0100
     6.3 @@ -0,0 +1,38 @@
     6.4 +#include <iostream>
     6.5 +#include <exception>
     6.6 +#include <memory>
     6.7 +
     6.8 +/** not needed, just for logging */
     6.9 +void* myMalloc(size_t size) {
    6.10 +	void* ptr = ::malloc(size);
    6.11 +	std::cout << "  allocated memory at: " << ptr << std::endl;
    6.12 +	return ptr;
    6.13 +}
    6.14 +
    6.15 +/** not needed, just for logging */
    6.16 +void myFree(void* ptr) {
    6.17 +	::free(ptr);
    6.18 +	std::cout << "  freed memory at: " << ptr << std::endl;
    6.19 +}
    6.20 +
    6.21 +void fxThrowing(bool fail, void* data) {
    6.22 +	std::cout << "  doing something with data " << data << std::endl;
    6.23 +	if (fail) throw std::logic_error("error from fxThrowing()");
    6.24 +}
    6.25 +
    6.26 +void fxAllocating(bool fail) {
    6.27 +	// std::shared_ptr<void> buf(malloc(486), free); // standard functions
    6.28 +	std::shared_ptr<void> buf(myMalloc(486), myFree); // our ones with logging
    6.29 +	fxThrowing(fail, buf.get());
    6.30 +}
    6.31 +
    6.32 +int main(int argc, char** argv) {
    6.33 +	bool fail = argc == 2 && std::string("fail") == argv[1];
    6.34 +	const char* name = "good-smart-pointer";
    6.35 +	std::cout << name << " (fail=" << fail << ")\n";
    6.36 +	try {
    6.37 +		fxAllocating(fail);
    6.38 +	} catch (const std::exception& e) {
    6.39 +		std::cout << "  caught exception: " << e.what() << std::endl;
    6.40 +	}
    6.41 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/good-vector.cpp	Wed Oct 30 02:44:44 2024 +0100
     7.3 @@ -0,0 +1,24 @@
     7.4 +#include <iostream>
     7.5 +#include <exception>
     7.6 +#include <vector>
     7.7 +
     7.8 +void fxThrowing(bool fail, void* data) {
     7.9 +	std::cout << "  doing something with data " << data << std::endl;
    7.10 +	if (fail) throw std::logic_error("error from fxThrowing()");
    7.11 +}
    7.12 +
    7.13 +void fxAllocating(bool fail) {
    7.14 +	std::vector<char> buf(486);
    7.15 +	fxThrowing(fail, buf.data());
    7.16 +}
    7.17 +
    7.18 +int main(int argc, char** argv) {
    7.19 +	bool fail = argc == 2 && std::string("fail") == argv[1];
    7.20 +	const char* name = "good-vector";
    7.21 +	std::cout << name << " (fail=" << fail << ")\n";
    7.22 +	try {
    7.23 +		fxAllocating(fail);
    7.24 +	} catch (const std::exception& e) {
    7.25 +		std::cout << "  caught exception: " << e.what() << std::endl;
    7.26 +	}
    7.27 +}