C++ automatic finalization or objects destruction - c++

In this example I faced the problem of copying the code:
void BadExample1() {
if (!Initialize1())
return;
if (!Initialize2()) {
Finalize1();
return;
}
if (!Initialize3()) {
Finalize1();
Finalize2();
return;
}
if (!Initialize4()) {
Finalize1();
Finalize2();
Finalize3();
return;
}
// some code..
Finalize1();
Finalize2();
Finalize3();
Finalize4();
}
Bnd here is a bad code structure. If I have a lot of constructs, the width of the code will be too large, this is also bad:
void BadExample2() {
if (Initialize1()) {
if (Initialize2()) {
if (Initialize3()) {
if (Initialize4()) {
if (Initialize5()) {
// some code..
Finalize5();
}
Finalize4();
}
Finalize3();
}
Finalize2();
}
Finalize1();
}
}
How can I save good code sturcture and solve code copying?
Finalize1/2/3 is a API functions and not my program classes.
Maybe some STL containers can solve it?
Maybe something like that?
void GoodExample() {
if (!Initialize1())
return;
RaiiWrapper<void(*)()> raii_wrapper1([]() {
Finalize1();
});
if (!Initialize2()) {
//Finalize1();
return;
}
RaiiWrapper<void(*)()> raii_wrapper2([]() {
Finalize2();
});
if (!Initialize3()) {
//Finalize1();
//Finalize2();
return;
}
RaiiWrapper<void(*)()> raii_wrapper3([]() {
Finalize3();
});
if (!Initialize4()) {
//Finalize1();
//Finalize2();
//Finalize3();
return;
}
RaiiWrapper<void(*)()> raii_wrapper4([]() {
Finalize4();
});
// some code..
//Finalize1();
//Finalize2();
//Finalize3();
//Finalize4();
}

Why not use real objects?
struct SetupPart1 {
SetupPart1 () { if (!Initialize1() throw std::runtime_error("Part1"); }
~SetupPart1 () { Finalize1(); }
};
and so on for part 2, 3, 4, etc.
Now your example looks like this:
void GoodExample() {
try {
SetupPart1 p1;
SetupPart2 p2;
SetupPart3 p3;
SetupPart4 p4;
// some code ...
}
catch { const std::runtime_error &ex ) {
std::cerr << "GoodExample Failed: " << ex.what << std::end;
}
}

You could streamline Marshall's suggestion and use the not-yet-standardized std::make_unique_resource() (this function is closely related to scope_guard, a contraption suggested by Andrei Alexandrescu some years ago and also in that proposal). That gives you an object with two functions - one to run at the variable scope's start, another to run at its end (i.e. on construction and destruction respectively).
Then, instead of defining four separate classes, you'd just write:
void GoodExample() {
auto r1 = std::make_unique_resource(Initialize1, Finalize1);
auto r2 = std::make_unique_resource(Initialize2, Finalize2);
auto r3 = std::make_unique_resource(Initialize3, Finalize3);
auto r4 = std::make_unique_resource(Initialize4, Finalize4);
// some code
}
The proposal has code for the implementation; and - it's not complex at all. So you could just copy the implementation and create your own not_std::make_unique_resource() function and related templated class(es).

Whenever you get a precious resource from an API, you need to wrap it as an object with the appropriate destructor. So, if Initialize1 initialises something1 then something1 should really be an object Something1 that knows how to initialise and how to finalise itself. Also, a failure to initialise should throw an exception (this is not done with fstream because fstream is older than this concept).
class Something1 {
public: Something1 () { if (!Initialize1()) throw resource_failed ("1"); }
~Something1 () { Finalize1(); }
}

Related

C++ Difficulty Creating Instance of Class within Singleton Class

I have a fairly good template (as in snippet of code) I pull out whenever I need a singleton class. I am now trying to apply it within my project to allow me to control a single instance of a web server. I can make a web server without encasing it in my class. When I try to encase it within the class I'm apparently too unskilled to pull it off.
I've tried the obvious Googling and searching here. I've read relevant posts. I am sure this does not mean I have a unique problem, just that I've not figured out the right way to fix it. Here's what I am working with:
webserver.h:
#include <ESP8266WebServer.h>
#include <FS.h>
class WebServer {
private:
// Singleton Declarations
static bool instanceFlag;
static WebServer *single;
WebServer() {}
// Other Declarations
FS *filesystem;
ESP8266WebServer server();
String getContentType(String);
bool handleFileRead(String);
public:
// Singleton Declarations
static WebServer* getInstance();
~WebServer() {instanceFlag = false;}
// Other Declarations
void initialize(int);
void handleLoop();
};
webserver.cpp:
#include "webserver.h"
bool WebServer::instanceFlag = false;
WebServer* WebServer::single = NULL;
WebServer* WebServer::getInstance() {
if(!instanceFlag) {
single = new WebServer();
instanceFlag = true;
return single;
} else {
return single;
}
}
void WebServer::initialize (int port) {
ESP8266WebServer server(port);
FS *filesystem;
filesystem->begin();
Serial.print("Open: http://");
Serial.print(WiFi.hostname().c_str());
Serial.println(".local");
server.onNotFound([]() {
if (!single->handleFileRead(single->server.uri())) {
single->server.send(404, "text/plain", "404: File not found.");
}
});
server.begin();
Serial.print("HTTP server started on port ");
Serial.print(port);
Serial.println(".");
}
String WebServer::getContentType(String filename) {
if (single->server.hasArg("download")) {
return "application/octet-stream";
} else if (filename.endsWith(".htm")) {
return "text/html";
} else if (filename.endsWith(".html")) {
return "text/html";
} else if (filename.endsWith(".css")) {
return "text/css";
} else if (filename.endsWith(".js")) {
return "application/javascript";
} else if (filename.endsWith(".png")) {
return "image/png";
} else if (filename.endsWith(".gif")) {
return "image/gif";
} else if (filename.endsWith(".jpg")) {
return "image/jpeg";
} else if (filename.endsWith(".ico")) {
return "image/x-icon";
} else if (filename.endsWith(".xml")) {
return "text/xml";
} else if (filename.endsWith(".pdf")) {
return "application/x-pdf";
} else if (filename.endsWith(".zip")) {
return "application/x-zip";
} else if (filename.endsWith(".gz")) {
return "application/x-gzip";
} else {
return "text/plain";
}
}
bool WebServer::handleFileRead(String path) {
Serial.println("handleFileRead: " + path);
if (path.endsWith("/")) {
path += "index.htm";
}
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if (filesystem->exists(pathWithGz) || filesystem->exists(path)) {
if (filesystem->exists(pathWithGz)) {
path += ".gz";
}
File file = filesystem->open(path, "r");
single->server.streamFile(file, contentType);
file.close();
return true;
}
return false;
}
void WebServer::handleLoop() {
single->server.handleClient();
}
The errors I am getting are all similar to the following:
src\webserver.cpp: In member function 'bool WebServer::handleFileRead(String)':
src\webserver.cpp:81:23: error: 'WebServer::single->WebServer::server' does not have class type
single->server.streamFile(file, contentType);
I get the idea of "does not have a class type", I just have no idea what it means here. In my mind, "single" is a pointer to the class so I'm unclear what that reference is not working.
Obviously, there are ample examples out there how to do a web server without encapsulating it. Other things I need to do for this project lend itself to creating that requirement.
There are some mistake in your code.
In webserver.h:
...
private:
// Singleton Declarations
static bool instanceFlag;
static WebServer *single;
WebServer() {}
// Other Declarations
FS *filesystem;
ESP8266WebServer *server; // <--- remove the parentheses and make it a pointer
String getContentType(String);
bool handleFileRead(String);
...
In webserver.cpp:
In WebServer::initialize I am guessing you want to initialize the class server and filesystem not locals, so it should probably look like this:
void WebServer::initialize (int port) {
server = new ESP8266WebServer(port);
filesystem = new FS();
...
}
And now everywhere you use the server you have to use the -> operator.
For example:
void WebServer::handleLoop() {
single->server->handleClient();
}
Please keep in mind that server and filesystem objects have to be deleted to avoid memory leaks.
EDIT:
You get the new error because FS has no constructor without arguments.
FS's constructor looks like this: FS(FSImplPtr impl) : _impl(impl) { }, here you can see that FSImplPtr is a typedef for std::shared_ptr<FileImpl>, so you need to provide this as a parameter.
It works your way, because SPIFFS's existence is declared here and is of type FS.
If you want to use SPIFFS, you have to use it like this: filesystem = &SPIFFS;, not like you mentioned in the comments (FS* filesystem = &SPIFFS;) because your way creates a new temporary variable named filesystem, and probably you expect to initiate the filesystem in the class, not a local one.

is there a better way to make this software flow

I have several functions that try and evaluate some data. Each function returns a 1 if it can successfully evaluate the data or 0 if it can not. The functions are called one after the other but execution should stop if one returns a value of 1.
Example functions look like so:
int function1(std::string &data)
{
// do something
if (success)
{
return 1;
}
return 0;
}
int function2(std::string &data)
{
// do something
if (success)
{
return 1;
}
return 0;
}
... more functions ...
How would be the clearest way to organise this flow? I know I can use if statements as such:
void doSomething(void)
{
if (function1(data))
{
return;
}
if (function2(data))
{
return;
}
... more if's ...
}
But this seems long winded and has a huge number of if's that need typing. Another choice I thought of is to call the next function from the return 0 of the function like so
int function1(std::string &data)
{
// do something
if (success)
{
return 1;
}
return function2(data);
}
int function2(std::string &data)
{
// do something
if (success)
{
return 1;
}
return function3(data);
}
... more functions ...
Making calling cleaner because you only need to call function1() to evaluate as far as you need to but seems to make the code harder to maintain. If another check need to be inserted into the middle of the flow, or the order of the calls changes, then all of the functions after the new one will need to be changed to account for it.
Am I missing some smart clear c++ way of achieving this kind of program flow or is one of these methods best. I am leaning towards the if method at the moment but I feel like I am missing something.
void doSomething() {
function1(data) || function2(data) /* || ... more function calls ... */;
}
Logical-or || operator happens to have the properties you need - evaluated left to right and stops as soon as one operand is true.
I think you can make a vector of lambdas where each lambdas contains specific process on how you evaluate your data. Something like this.
std::vector<std::function<bool(std::string&)> listCheckers;
listCheckers.push_back([](std::string& p_data) -> bool { return function1(p_data); });
listCheckers.push_back([](std::string& p_data) -> bool { return function2(p_data); });
listCheckers.push_back([](std::string& p_data) -> bool { return function3(p_data); });
//...and so on...
//-----------------------------
std::string theData = "Hello I'm a Data";
//evaluate all data
bool bSuccess = false;
for(fnChecker : listCheckers){
if(fnChecker(theData)) {
bSuccess = true;
break;
}
}
if(bSuccess ) { cout << "A function has evaluated the data successfully." << endl; }
You can modify the list however you like at runtime by: external objects, config settings from file, etc...

Calling a method async does not work anymore after refactoring

In order to separate my GUI from the logic (which fetches data from a REST service), I refactored some logic into a controller.
Now, only part of the logic seems to work.
The GUI component looks like this after refactoring (I am using the JUCE framework)
#pragma once
#include "../../JuceLibraryCode/JuceHeader.h"
#include "../../GUI.Controller/includes/ProjectEntryListController.h"
#include "ProjectEntryListComponent.h"
#include "LocalProjectEntryComponent.h"
class ProjectBrowserTabComponent : public TabbedComponent
{
public:
ProjectBrowserTabComponent();
~ProjectBrowserTabComponent();
private:
ProjectEntryListComponent m_remote_proj;
ProjectEntryListComponent m_local_proj;
ProjectEntryListController *pelccont = new ProjectEntryListController(&m_remote_proj);
ProjectEntryListController *pelccont2 = new ProjectEntryListController(&m_local_proj);
};
The GUI controller looks like this:
#define BOOST_THREAD_PROVIDES_FUTURE
#include "../includes/ProjectEntryListController.h"
template<typename R>
bool isReady(std::future<R> const& f)
{
Logger::writeToLog("check future");
return f.wait_for(std::chrono::seconds(-1)) == std::future_status::ready;
}
ProjectEntryListController::ProjectEntryListController(ProjectEntryListComponent *comp) {
m_comp = comp;
requestProjects();
}
void ProjectEntryListController::requestProjects()
{
Logger::writeToLog("requesting projects");
projectsFuture = std::async(std::launch::async, &ProjectsController::getProjects, &pc);
Logger::writeToLog("requested projects");
}
void ProjectEntryListController::backgroundCheckFuture()
{
timer = new boost::asio::deadline_timer(io_service, boost::posix_time::seconds(interval_secs));
timer->async_wait(boost::bind(&ProjectEntryListController::fetchData, this, boost::asio::placeholders::error, timer));
ioSvcFuture = std::async(std::launch::async, static_cast<size_t(boost::asio::io_service::*)()>(&boost::asio::io_service::run), &io_service);
}
void ProjectEntryListController::initData() {
requestProjects();
backgroundCheckFuture();
}
void ProjectEntryListController::fetchData(const boost::system::error_code& /*e*/,
boost::asio::deadline_timer* tmr) {
if (isReady(projectsFuture)) {
projects = projectsFuture.get();
for (auto project : projects)
{
ProjectEntryComponent *pec = new ProjectEntryComponent(std::to_string(project.getId()), "222");
m_comp->addListEntry(pec);
m_comp->repaint();
}
Logger::writeToLog("got projs");
}
else {
tmr->expires_at(tmr->expires_at() + boost::posix_time::seconds(interval_secs));
tmr->async_wait(boost::bind(&ProjectEntryListController::fetchData, this, boost::asio::placeholders::error, tmr));
}
}
The requestProjects method's log messages are appearing in my console, but not the log message of the getProjects method I am calling asynchronously:
std::vector<Project> ProjectsController::getProjects() {
std::vector<Project> result;
if(serviceClient != nullptr) {
try
{
std::this_thread::sleep_for(std::chrono::seconds());
std::cout << "controller requested projs\n";
result = serviceClient->getAvailableProjects();
}
catch (const std::exception&)
{
}
}
return result;
}
However, when I debug into the code, the debugger (using VS 2015) also is able to step to the log message.
What am I doing wrong?
Actually I solved this now.
1.) I was calling the wrong method requestProjects instead of initData
2.) I couldn't see the result because the implementation of ProjectEntryComponent::ProjectEntryComponent(std::string name, std::string version) was missing

RxCpp: how to control subject observer's lifetime when used with buffer_with_time

The purpose of the following code is to have various classes publish data to an observable. Some classes will observe every data, some will observe periodically with buffer_with_time().
This works well until the program exits, then it crashes, probably because the observer using buffer_with_time() is still hanging on to some thread.
struct Data
{
Data() : _subscriber(_subject.get_subscriber()) { }
~Data() { _subscriber.on_completed(); }
void publish(std::string data) { _subscriber.on_next(data); }
rxcpp::observable<std::string> observable() { return _subject.get_observable(); }
private:
rxcpp::subjects::subject<std::string> _subject;
rxcpp::subscriber<std::string> _subscriber;
};
void foo()
{
Data data;
auto period = std::chrono::milliseconds(30);
auto s1 = data.observable()
.buffer_with_time(period , rxcpp::observe_on_new_thread())
.subscribe([](std::vector<std::string>& data)
{ std::cout << data.size() << std::endl; });
data.publish("test 1");
data.publish("test 2");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
}
I tried calling "s1.unsubscribe()", and various as_blocking(), from(), merge(), but still can't get the program to exit gracefully.
Note that I used "subjects" here because "publish" can then be called from different places (which can be from different threads). I am not sure if this is the best mechanism to do that, I am open to other ways to accomplish that.
Advice?
This is very close to working..
However, having the Data destructor complete the input while also wanting the subscription to block the exit of foo until input is completed makes this more complex.
Here is a way to ensure that foo blocks after Data destructs. This is using the existing Data contract.
void foo1()
{
rxcpp::observable<std::vector<std::string>> buffered;
{
Data data;
auto period = std::chrono::milliseconds(30);
buffered = data.observable()
.buffer_with_time(period , rxcpp::observe_on_new_thread())
.publish().ref_count();
buffered
.subscribe([](const std::vector<std::string>& data)
{ printf("%lu\n", data.size()); },
[](){printf("data complete\n");});
data.publish("test 1");
data.publish("test 2");
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
}
buffered.as_blocking().subscribe();
printf("exit foo1\n");
}
Alternatively, the changing the shape of Data (add a complete method) would allow the following code:
struct Data
{
Data() : _subscriber(_subject.get_subscriber()) { }
~Data() { complete(); }
void publish(std::string data) { _subscriber.on_next(data); }
void complete() {_subscriber.on_completed();}
rxcpp::observable<std::string> observable() { return _subject.get_observable(); }
private:
rxcpp::subjects::subject<std::string> _subject;
rxcpp::subscriber<std::string> _subscriber;
};
void foo2()
{
printf("foo2\n");
Data data;
auto newthread = rxcpp::observe_on_new_thread();
auto period = std::chrono::milliseconds(30);
auto buffered = data.observable()
.buffer_with_time(period , newthread)
.tap([](const std::vector<std::string>& data)
{ printf("%lu\n", data.size()); },
[](){printf("data complete\n");});
auto emitter = rxcpp::sources::timer(std::chrono::milliseconds(0), newthread)
.tap([&](long) {
data.publish("test 1");
data.publish("test 2");
data.complete();
});
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
buffered.combine_latest(newthread, emitter).as_blocking().subscribe();
printf("exit foo2\n");
}
I think that this better expresses the dependencies..

How to run code even when an exception happens

I have a code like this:
try
{
do_some_processing();
// Write Log to appropriate place.
}
catch
{
// add debug info to log
// Write Log to appropriate place.
processException();
}
As you can see I need to write log when there is an exception and when there is not.
Is there any way that I can do in one place? and not copy it twice?
as far as I know, finally is called after exception is processed and not before it. Am I right?
I'd use RAII idiom
class RaiiLogger {
public:
RaiiLogger() : exception_fired_(true) {}
void set_success() {
exception_fired_ = false;
}
~RaiiLogger() {
if (exception_fired_) {
// log it
} else {
// log it
}
}
private:
bool exception_fired_;
};
void do_work() {
RaiiLogger logger;
try {
// do some work
logger.set_success();
} catch(...) {
// handle exception
}
}
int main() {
// your code goes here
do_work();
return 0;
}
Just move it outside of the try-catch block:
try
{
do_some_processing();
}
catch
{
// add debug info to log
processException();
}
// Write Log to appropriate place.
How about:
try{
do_some_processing();
}catch{
// add debug info to log
processException();
}
// write log to appropriate place