I've come across a situation where I have a bunch of "systems" that need to be initialized in sequence, with the next system only being initialized if all of the proceeding systems initialized successfully.
This has led me to a whole slew of nested if - else statements. Here's some pseudo-code for visualization.
bool mainInit () {
if (!system1Init ()) {
reportError (); // some error reporting function
}
else {
if (!system2Init ()) {
reportError ();
}
else {
if (!system3Init ()) {
// ... and so on
I find that this starts to look like a mess when you get even a handful of levels to it.
Now I thought of using a switch statement instead, starting at the first case and falling through to the other cases on success, only breaking if there's an error.
bool mainInit () {
switch (1) {
case 1:
if (!system1Init ()) {
reportError ();
break;
}
case 2:
if (!system2Init ())
reportError ();
break;
}
// ....
}
Now, I like this a lot better. I find it much easier to read, especially with some decent comments, but I'm fairly new to programming.
So, my question is: Seeing how this is not how switch statements are traditionally used(at least from what I've seen), is something like this acceptable, or would this be considered bad form?
Being new to programming, I'm trying not to develop too many bad habits that might frustrate and make things more difficult for other programmers down the road.
I did a search, but most of what I found had to do with replacing chains of if - else if statements, not replacing nested ones.
Reference all of the systems in an array, for example an std::vector<mySystem*>, and loop over them sequentially, breaking off on the first fail. This way your entire code is reduced to less than 5 lines of code, even for 500+ systems.
The suggested switch hack is an evil example of XY problem solving: your real problem is that you don't have the array of systems, and are using named variables, thus eliminating all options to more flexibly use all systems, like in a loop.
Assuming that all your system#Init() calls are known at compile time, you can very easily put them in a table and then iterate over that table.
typedef (*system_init)(void);
system_init initialization_functions[] =
{
system1Init,
system2Init,
system3Init,
...
systemNInit
};
bool mainInit()
{
for(size_t idx(0); idx < sizeof(initialization_functions) / sizeof(initialization_functions[0]); ++idx)
{
if(!initialization_functions[idx]())
{
ReportError();
return false;
}
}
return true;
}
However, your existing code looks incorrect since the first mainInit() only calls system1Init() and then exits. Probably not what you wanted in the first place.
if(!system1Init())
{
ReportError();
return false;
}
// if you add an else, the system2Init() does not get called
// even if system1Init() succeeds
if(!system2Init())
{
ReportError();
return false;
}
[...]
return true;
Would the switch answer your problem? Not as it was written. That is, if you wanted to call the mainInit() function with a counter, it could be useful. Drupal uses that mechanism:
bool mainInit(int idx)
{
bool r(true);
switch(idx)
{
case 1:
r = system1Init();
break;
case 2:
r = system2Init();
break;
[...]
}
if(!r)
{
ReportError();
}
return r
}
Note that the table mechanism works the same way as the switch. As long as all the code is found in the systemNInit() functions (and it should be), the switch does not add anything, so you could do something like this too:
bool mainInit(int idx)
{
if(idx < 0 || idx >= sizeof(initialization_functions) / sizeof(initialization_functions[0]))
{
throw std::range_error("index out of bounds");
}
if(!initialization_functions[idx]())
{
ReportError();
return false;
}
return true;
}
Calling the mainInit() with an index can be helpful in case you want to "de-initialize" properly:
int main()
{
for(size_t idx(0); idx < ...; ++idx)
{
if(!mainInit(idx))
{
while(idx > 0)
{
--idx;
mainDeinit(idx);
}
exit(1);
}
}
...app do something here...
}
Use custom exceptions with clear error messages and add a try-catch-report-die around the code in main(). Exceptions are there to specifically make your case look good by making "bad path" implicit.
void initX() { ...; throw std::invalid_argument_exception("..."); }
int main() {
try {
init1(); init2(); ... run();
return 0;
} catch (std::exception const& e) {
log(e.what()); exit 42;
}
}
I'd do it this way:
bool mainInit () {
if (!system1Init ()) {
return(false);
}
if (!system2Init ()) {
return(false);
}
if (!system3Init ()) {
return(false);
}
//...
return(true);
}
//...
if(!mainInit()) {
reportError();
}
Related
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...
I have the following code which returns ERROR in many lines:
bool func()
{
if (acondition)
{
return 0;
}
return 1;
}
int cmdfun()
{
other_funcs;
if (func()) return ERROR#NUMBER;
other_funcs;
if (func()) return ERROR#NUMBER;
}
But I found its becoming longer and longer. How can I encapsulate return ERROR#NUMBER into func() also? Or any way to encapsulate if (func()) return ERROR; into another independent function?
You can't really achieve this using return on its own.
But you could throw an exception in func which will bubble up the call stack, in the way you seem to want program control to:
struct myexception{}; /*ToDo - inherit from std::exception?*/
bool func()
{
if (acondition){
return 0; /*normal behaviour, perhaps make `func` void if not needed?*/
}
throw myexception();
}
cmdfun then takes the form:
int cmdfun()
{
other_funcs;
func();
other_funcs;
func();
/* don't forget to return something*/
}
Finally, make sure you catch the exception in the caller to cmdfun.
As I said it is not an exception and cannot be handled by std::exception, it is just an error message and ERROR#NUMBER is just another macro. And I cannot access to the caller to cmdfun(). So unable to adopt the first answer. But after asked someone else, it is possible to encapsulate returns and save time when typing them, though it's not recommended, but in this particular case, I can use macro. A complete example is given below:
#include <iostream>
using namespace std;
#define CHECK_VEC(acondition)\
if(checkcondition(acondition)) return -1;
bool checkcondition(bool acondition)
{
if (acondition) return 1;
return 0;
}
int fun_called_by_main()
{
int a = 5 + 4;
bool acondition = a;
CHECK_VEC(acondition);
return 1;
}
int main()
{
int a = fun_called_by_main();
cout << a << endl;
cin.get();
return 0;
}
If I understood corectly your question, you are asking for an 'error reporter' for your own errors. There are 2 solutions for 2 separate cases:
Case 1 - you still want to use a return statement to make an 'error reporter':
To do this, you'll have to make another function or just learn how to use goto. However, you don't need to - your function returns a boolean(bool) - which means you only have 2 possible results: 0 (False) and 1 (True)
bool func()
{
if (acondition)
{
return (bool)0; // False (no error)
}
return (bool)1; // True (error)
// Note: I used (bool)0 and (bool)1 because it is
// more correct because your returning type is bool.
}
void errorcase(bool trueorfalse)
{
switch(trueorfalse)
{
case False:
... // your code (func() returned 0)
break;
default:
... // your code (func() returned 1)
break;
// Note that you will not need to check if an error occurred every time.
}
return;
}
int cmdfun()
{
... // your code
errorcase(func());
... // again - your code
return 0; // I suppouse that you will return 0...
}
But I think that the second case is more interesting (unfortunetly it is also preety hard to understand as a beginner and the first solution might be a lot easier for you):
Case 2 - you decided to do it somehow else - that's by learning throw and catch - I won't repeat the answer because it is already given: #Bathsheba answered preety good...
This might be a non-sense question, but i'm kind of stuck so I was wondering if someone can help. I have the following code:
bool while_condition=false;
do{
if(/*condition*/){
//code
}
else if(/*condition*/){
//code
}
else if(/*condition*/){
//code
}
...//some more else if
else{
//code
}
check_for_do_while_loop(while_condition, /*other parameters*/);
}while(while_condition);
the various if and else if exclude with each other but each have other if inside; if a certain condition is met (which can't be specified in a single if statement), then the code return a value and the do while loop is ended. But if, after entering a single else if, the conditions inside aren't met the code exit without actually doing nothing, and the while loop restart the whole.
I want the program to remember where he entered and avoid that part of the code, i.e. to avoid that specific else if he entered without any result, so he can try entering another else if. I thought about associating a boolean to the statements but I'm not quite sure on how to do it. Is there a way which allows me not to modify the code structure too much?
To give an idea of one way of approaching this that avoid loads of variables, here is an outline of how you might data-drive a solution.
class TestItem
{
public:
typedef bool (*TestFuncDef)(const state_type& state_to_test, std::shared_ptr<result_type>& result_ptr);
TestItem(TestFuncDef test_fn_parm)
{
test_fn = test_fn_parm;
already_invoked = false;
}
bool Invoke(const state_type& state_to_test, std::shared_ptr<result_type>& result_ptr)
{
already_invoked = true;
return test_fn(state_to_test, result_ptr);
}
bool AlreadyInvoked() const {return already_invoked; }
private:
TestFuncDef test_fn;
bool already_invoked;
};
std::shared_ptr<result_type> RunTest(std::list<TestItem>& test_item_list, state_type& state_to_test)
{
for(;;) {
bool made_a_test = false;
for (TestItem& item : test_item_list) {
std::shared_ptr<result_type> result_ptr;
if (!item.AlreadyInvoked()) {
made_a_test = true;
if (item.Invoke(state_to_test, result_ptr)) {
return result_ptr;
}
else
continue;
}
}
if (!made_a_test)
throw appropriate_exception("No conditions were matched");
}
}
This is not supposed to be a full solution to your problem but suggests another way of approaching it.
The important step not documented here is to build up the std::list of TestItems to be passed to RunTest. Code to do so might look like this
std::list<TestItem> test_item_list;
test_item_list.push_back(TestItem(ConditionFn1));
test_item_list.push_back(TestItem(ConditionFn2));
The definition of ConditionFn1 might look something like
bool ConditionFn1(const state_type& state_to_test, std::shared_ptr<result_type>& result_ptr)
{
// Do some work
if (....)
return false;
else {
result_ptr.reset(new result_type(some_args));
return true;
}
}
how can i exit from nested while() or for() without goto?
for example if i use three loops like below in a function:
void myfun(){
for (;;)
{
while( true )
{
for (;;)
{
//what is the exit code of all loop() from here?
}
}
}
}
using break; only can exit from one loop,
but how can i exit all loops ?
the loops can be limited by counter or unlimited.
I personally would rewrite the code so that you don't have a nested loop in the first place. Something like this:
bool myFun2
{
for (;;)
{
if(something) return true;
}
// If the loop isn't "forever", return false here?
}
bool myFun1()
{
while( true )
{
if (myFun2()) return true;
}
// return false here if needed.
}
void myfun()
{
for (;;)
{
if(myFun1()) break;
}
}
This becomes much easier to follow than trying to figure out which conditions some exitLoop variable gets set, for example.
You can't, you need another break at while context or change yours loops usign a variable as a exit flag:
bool exit = false;
for (;;){
while (!exit){
for (;;){
exit = true;
break;
}
}
if (exit) break;
}
An so on for as many loop do you have in your code
If you want to jump out of the function that is leave the function then you should use return. However if you want to just jump off the nested loops & not out of the function then you can throw an exception. This method will help you from breaking the code into several functions as some have done. However exceptions are meant for library designers & we should avoid using them too much. Personally speaking using goto is the best thing in this case but as you asked against it, hence I'm saying so. Well then your code will look like this :-
void myfun()
{
try
{
for (;;)
{
while( true )
{
for (;;)
{
if (/*some condition*/)
throw false;
}
}
}
}
catch (bool)
{
cout<<"caught";
}
// do stuffs if your code is successful that is you don't break out
}
I am trying to refactor the following code, as I don't think it is structured well.
Can you think of a more elegant way to do this?
Bar::Bar()
{
m_iter1 = 0;
m_iter2 = 0;
}
bool Bar::foo()
{
_reinitialize();
for (; m_iter1 < 2; m_iter1++, m_iter2 = 0) {
_log("TRYING METHOD: [%d]", m_iter1);
if (_something_wrong(m_iter1)) {
return false;
}
for (; m_iter2 < 6; m_iter2++) {
if (_try_with_these_params(m_iter1, m_iter2, ...)) {
m_status = success;
// store next iteration in case we need to retry.
m_iter2++;
return true;
}
}
}
return false;
}
bool try_foo(Bar& bar)
{
if (bar.foo()) {
if (meet_some_criteria) {
return true;
} else {
bar.invalidate();
// retry. the Bar object stores the state.
try_foo(bar);
}
} else {
return false;
}
}
int main()
{
Bar bar;
if (try_foo(bar)) {
_log("SUCCESS");
} else {
_log("FAILURE");
}
}
The code loops over different parameter sets and tries to perform some action with these parameters. If the action is successful, then external code may invalidate the action and attempt to retry. The object which performs the action stores the state, so that external code may retry and re-enter the parameter loop at the place it left off.
The output using one parameters affect others, so the calculations need to be accomplished locally within the Bar class.
I would like to extend this idea to more dimensions, but doing so with the current design is clumsy.
A lot here depends on how expensive the various actions are.
If initially generating a candidate parameter set is cheap (and the set isn't too large), then you might want to just generate all the candidate sets, then give that result to the external code and try each in turn until you find one that the external code will accept.