Parallell while loops without using threads - c++

(C++)
Is there any possibility to run two parallel while loops without using threads? I have tried putting them one after another, both in one for loop, but it doesn't work for me because the variable that I'm using in while condition is getting changed through 1st loop and I need it to be the same for both loops.
Here's the code:
for (size_t j = 0; j < word.length(); j++)
{
while (word[j] != tmp->data)
{
counter1++;
tmp = tmp->next;
}
while (word[j] != tmp->data)
{
counter2++;
tmp = tmp->previous;
}
}

From the comment:
I'm getting the letter from a string and trying to find out which path is shorter to get to the same letter in alphabet, going forward or backwards. I am using cyclical doubly linked list.
Sounds like you just want one while loop with two tmp pointers:
for (size_t j = 0; j < word.length(); j++)
{
while (word[j] != tmp1->data && word[j] != tmp2->data)
{
counter++;
tmp1 = tmp1->next;
tmp2 = tmp2->previous;
}
}

No this is not possible without threads (or you can use interprocess but I guess this is not your point)
You can avoid using "manual" threading though with std::future and std::async
You can make each search a function like this:
int forward(std::string word)
{
int counter = 0;
for (size_t j = 0; j < word.length(); j++)
{
while (word[j] != tmp->data)
{
counter++;
tmp = tmp->next;
}
}
return counter;
}
Or the respective backwards
And call them like this.
std::string word = //....
auto res1 = std::async(std::launch::async, forward,word);
auto res2 = std::async(std::launch::async, forward,word);
//do whatever....
int counter1 = res1.get(); //get the result
int counter2 = res2.get();
Note though that get will block until the threads are done. But they will run in parallel.
In your case depending on the size of the string/alphabet and the algorithm though I doubt you get much benefit from doing this in multiple threads. The threading overhead can take longer than the whole calculation so you should measure if this may be faster doing this single-threaded.

Related

If statement branch prediction issue

I am implementing a pattern search algorithm that has a vital if statement that seems to be unpredictable in it's result. Random files are searched and thus sometimes the branch predictions are okay and sometimes they can be terrible if the file is completely random. My goal is to eliminate the if statement and I have tried but it has yielded slow results like preallocating a vector. The number of pattern possibilities can be very large so preallocating takes up a lot of time. I therefore have the dynamic vector where I initialize them all with NULL up front and then check with the if statement if a pattern is present. The if seems to be killing me and specifically the cmp assembly statement. Bad branch predictions are scrapping the pipeline a lot and causing huge slow downs. Any ideas would be great as to eliminate the if statement at line 17...stuck in a rut.
for (PListType i = 0; i < prevLocalPListArray->size(); i++)
{
vector<vector<PListType>*> newPList(256, NULL);
vector<PListType>* pList = (*prevLocalPListArray)[i];
PListType pListLength = (*prevLocalPListArray)[i]->size();
PListType earlyApproximation = ceil(pListLength/256);
for (PListType k = 0; k < pListLength; k++)
{
//If pattern is past end of string stream then stop counting this pattern
if ((*pList)[k] < file->fileStringSize)
{
uint8_t indexer = ((uint8_t)file->fileString[(*pList)[k]]);
if(newPList[indexer] != NULL) //Problem if statement!!!!!!!!!!!!!!!!!!!!!
{
newPList[indexer]->push_back(++(*pList)[k]);
}
else
{
newPList[indexer] = new vector<PListType>(1, ++(*pList)[k]);
newPList[indexer]->reserve(earlyApproximation);
}
}
}
//Deallocate or stuff patterns in global list
for (int z = 0; z < newPList.size(); z++)
{
if(newPList[z] != NULL)
{
if (newPList[z]->size() >= minOccurrence)
{
globalLocalPListArray->push_back(newPList[z]);
}
else
{
delete newPList[z];
}
}
}
delete (*prevLocalPListArray)[i];
}
Here is the code without indirection with the changes proposed...
vector<vector<PListType>> newPList(256);
for (PListType i = 0; i < prevLocalPListArray.size(); i++)
{
const vector<PListType>& pList = prevLocalPListArray[i];
PListType pListLength = prevLocalPListArray[i].size();
for (PListType k = 0; k < pListLength; k++)
{
//If pattern is past end of string stream then stop counting this pattern
if (pList[k] < file->fileStringSize)
{
uint8_t indexer = ((uint8_t)file->fileString[pList[k]]);
newPList[indexer].push_back((pList[k] + 1));
}
else
{
totalTallyRemovedPatterns++;
}
}
for (int z = 0; z < 256; z++)
{
if (newPList[z].size() >= minOccurrence/* || (Forest::outlierScans && pList->size() == 1)*/)
{
globalLocalPListArray.push_back(newPList[z]);
}
else
{
totalTallyRemovedPatterns++;
}
newPList[z].clear();
}
vector<PListType> temp;
temp.swap(prevLocalPListArray[i]);
}
Here is the most up to date program that manages to not use 3 times the memory and does not require an if statement. The only bottleneck seems to be the newPList[indexIntoFile].push_back(++index); statement. This bottleneck could be cache coherency issues when indexing the array because the patterns are random. When i search a binary files with just 1s and 0s I don't have any latency with indexing the push back statement. That is why I believe it is cache thrashing. Do you guys see any room for optimization in this code still? You guys have been a great help so far. #bogdan #harold
vector<PListType> newPList[256];
PListType prevPListSize = prevLocalPListArray->size();
PListType indexes[256] = {0};
PListType indexesToPush[256] = {0};
for (PListType i = 0; i < prevPListSize; i++)
{
vector<PListType>* pList = (*prevLocalPListArray)[i];
PListType pListLength = (*prevLocalPListArray)[i]->size();
if(pListLength > 1)
{
for (PListType k = 0; k < pListLength; k++)
{
//If pattern is past end of string stream then stop counting this pattern
PListType index = (*pList)[k];
if (index < file->fileStringSize)
{
uint_fast8_t indexIntoFile = (uint8_t)file->fileString[index];
newPList[indexIntoFile].push_back(++index);
indexes[indexIntoFile]++;
}
else
{
totalTallyRemovedPatterns++;
}
}
int listLength = 0;
for (PListType k = 0; k < 256; k++)
{
if( indexes[k])
{
indexesToPush[listLength++] = k;
}
}
for (PListType k = 0; k < listLength; k++)
{
int insert = indexes[indexesToPush[k]];
if (insert >= minOccurrence)
{
int index = globalLocalPListArray->size();
globalLocalPListArray->push_back(new vector<PListType>());
(*globalLocalPListArray)[index]->insert((*globalLocalPListArray)[index]->end(), newPList[indexesToPush[k]].begin(), newPList[indexesToPush[k]].end());
indexes[indexesToPush[k]] = 0;
newPList[indexesToPush[k]].clear();
}
else if(insert == 1)
{
totalTallyRemovedPatterns++;
indexes[indexesToPush[k]] = 0;
newPList[indexesToPush[k]].clear();
}
}
}
else
{
totalTallyRemovedPatterns++;
}
delete (*prevLocalPListArray)[i];
}
Here are the benchmarks. I didn't think it would be readable in the comments so I am placing it in the answer category. The percentages to the left define how much time is spent percentage wise on a line of code.

Applying OpenMP to particular nested loops in C++

I've a problem in parallelizing a piece of code with openmp, I think that there is a conceptual problem with some operations that have to be made sequentially.
else if (PERF_ROWS <= MAX_ROWS && function_switch == true)
{
int array_dist_perf[PERF_ROWS];
int array_dist[MAX_ROWS];
#pragma omp parallel for collapse(2)
for (int i = 0; i < MAX_COLUMNS;
i = i + 1 + (i % PERF_CLMN == 0 ? 1:0))
{
for (int j = 0; j < PERF_ROWS; j++) //truncation perforation
{
array_dist_perf[j] = abs(input[j] - input_matrix[j][i]);
}
float av = mean(PERF_ROWS, array_dist_perf);
float score = score_func(av);
if (score > THRESHOLD_SCORE)
{
for (int k = 0; k < MAX_ROWS; k++)
{
array_dist[k] = abs(input[k] - input_matrix[k][i]);
}
float av_real = mean(MAX_ROWS, array_dist);
float score_real = score_func(av_real);
rank_function(score_real, i);
}
}
}
The error is that "collapsed loops are not perfectly nested". I'm using Clion on g++-5. Thanks in advance
First of all, perfectly nested loops have the following form:
for (init1; cond1; inc1)
{
for (init2; cond2; inc2)
{
...
}
}
Notice that the body of the outer loop consists solely of the inner loop and nothing else. This is definitely not the case with your code - you have plenty of other statements following the inner loop.
Second, your outer loop is not in the canonical form required by OpenMP. Canonical are loops for which the number of iterations and the iteration step can be easily pre-determined. Since what you are doing is skip an iteration each time i is a multiple of PERF_CLMN, you can rewrite the loop as:
for (int i = 0; i < MAX_COLUMNS; i++)
{
if (i % PERF_CLMN == 1) continue;
...
}
This will create work imbalance depending on whether MAX_COLUMNS is a multiple of the number of threads or not. But there is yet another source or imbalance, namely the conditional evaluation of rank_function(). You should therefore utilise dynamic scheduling.
Now, apparently both array_dist* loops are meant to be private, which they are not in your case and that will result in data races. Either move the definition of the arrays within the loop body or use the private() clause.
#pragma omp parallel for schedule(dynamic) private(array_dist_perf,array_dist)
for (int i = 0; i < MAX_COLUMNS; i++)
{
if (i % PERF_CLMN == 1) continue;
...
}
Now, for some unsolicited optimisation advice: the two inner loops are redundant as the first one is basically doing a subset of the work of the second one. You can optimise the computation and save on memory by using a single array only and let the second loop continue from where the first one ends. The final version of the code should look like:
else if (PERF_ROWS <= MAX_ROWS && function_switch == true)
{
int array_dist[MAX_ROWS];
#pragma omp parallel for schedule(dynamic) private(array_dist)
for (int i = 0; i < MAX_COLUMNS; i++)
{
if (i % PERF_CLMN == 1) continue;
for (int j = 0; j < PERF_ROWS; j++) //truncation perforation
{
array_dist[j] = abs(input[j] - input_matrix[j][i]);
}
float av = mean(PERF_ROWS, array_dist);
float score = score_func(av);
if (score > THRESHOLD_SCORE)
{
for (int k = PERF_ROWS; k < MAX_ROWS; k++)
{
array_dist[k] = abs(input[k] - input_matrix[k][i]);
}
float av_real = mean(MAX_ROWS, array_dist);
float score_real = score_func(av_real);
rank_function(score_real, i);
}
}
}
Another potential for optimisation lies in the fact that input_matrix is not accessed in a cache-friendly way. Transposing it will result in columns data being stored continuously in memory and improve the memory access locality.

How to stop a nested for loop

I want both loops to stop as soon as I find an object that has the same position in x.
Here is my C++ code:
for(int i = 0; i < sizeArray; ++i){
for(int j = i; j > 0; --j){
if (s[i].positionX == s[j-1].positionX){
s[i].positionY = s[j-1].positionY;
}
}
}
If I use break; it only breaks out of the inner for loop. What is the best way to stop both?
Options:
Set the indexes of the loops to max value (or min value) to terminate the loop.
Put all this inside a function and use return.
Use a goto
Use a Lambda
Set a boolean stop code to true, break, then listen for break and break out of other loop?
?
To break out of the innermost for loop, use break.
To break out of the outermost one, either use goto or use a combination of break and a "should stop" flag.
I would suggest lambda:
auto do_work = [&] {
for(int i = 0; i < sizeArray; ++i){
for(int j = i; j > 0; --j){
if (s[i].positionX == s[i-1].positionX){
s[i].positionY = s[i-1].positionY;
return;
}
}
}
};
do_work(); //you can call this multiple times if you need to!
No break, no goto. :-)
It serves the same purpose as break and goto in this case, but the technique seems to be clean, at least to me. Also, once you have the lambda with a name (a good name), you can use it multiple times if you need to — so this technique increases the code readability and encourages code-reuse.
Of course, if you don't need to call this multiple times, then probably you don't need a name. You just could do this:
[&]
{
//your code with the added return statement.
}();
But as I said, name increases readability even if you don't call it multiple times.
If you cannot use lambda for some reason, then you could still avoid using an extra variable such as stop and the extra work involving it (as #ssantos's answer suggested):
for(int i = 0; i < sizeArray; ++i){
for(int j = i; j > 0; --j){
if (s[i].positionX == s[i-1].positionX){
s[i].positionY = s[i-1].positionY;
i = sizeArray; //it will break the outer loop!
break;
}
}
}
Hope that helps.
I'm guessing you ask for stopping a for loop. The keyword you're looking for is break. However, if you want to exit both for loops, you'll need to add a variable to your code.-
bool stop = false;
for(int i = 0; i < sizeArray; ++i){
for(int j = i; j > 0; --j){
if (s[i].positionX == s[i-1].positionX){
s[i].positionY = s[i-1].positionY;
stop = true;
break;
}
}
if (stop) {
break;
}
}
Put the code you posted in its own function and return out of it after the assignment.
You can stop a for loop with break.
With nested for loops, things are not so easy. You can achieve your goal
either with setting a flag (done = 1; and use it with for(int j = i; j > 0 && !done; --j))
or with goto. Although goto is frowned upon by some people, it can, if used correctly and with care, be a legitimate solution for some problems, such as error handling, or in general, "finished handling".
Try the following
bool match = false;
for(int i = 0; i < sizeArray && !match; ++i){
for(int j = i; j > 0 && !match; --j){
if ( match = ( s[i].positionX == s[i-1].positionX ) ){
s[i].positionY = s[i-1].positionY;
}
}
}
Another way is the following
for(int i = 0; i < sizeArray; ++i){
int j = i;
while ( j != 0 && s[i].positionX != s[i-1].positionX ) --j;
if ( j != 0 ) {
s[i].positionY = s[i-1].positionY;
break;
}
}

c++ counting sort

I tried to write a countingsort, but there's some problem with it.
here's the code:
int *countSort(int* start, int* end, int maxvalue)
{
int *B = new int[(int)(end-start)];
int *C = new int[maxvalue];
for (int i = 0; i < maxvalue; i++)
{
*(C+i) = 0;
}
for (int *i = start; i < end; i++)
{
*(C+*i) += 1;
}
for (int i = 1; i < maxvalue-1 ; i++)
{
*(C+i) += *(C+i-1);
}
for (int *i = end-1; i > start-1; i--)
{
*(B+*(C+(*i))) = *i;
*(C+(*i)) -= 1;
}
return B;
}
In the last loop it throws an exception "Acces violation writing at location: -some ram address-"
Where did I go wrong?
for (int i = 1; i < maxvalue-1 ; i++)
That's the incorrect upper bound. You want to go from 1 to maxvalue.
for (int *i = end-1; i > start-1; i--)
{
*(B+*(C+(*i))) = *i;
*(C+(*i)) -= 1;
}
This loop is also completely incorrect. I don't know what it does, but a brief mental test shows that the first iteration sets the element of B at the index of the value of the last element in the array to the number of times it shows. I guarantee that that is not correct. The last loop should be something like:
int* out = B;
int j=0;
for (int i = 0; i < maxvalue; i++) { //for each value
for(j<C[i]; j++) { //for the number of times its in the source
*out = i; //add it to the output
++out; //in the next open slot
}
}
As a final note, why are you playing with pointers like that?
*(B + i) //is the same as
B[i] //and people will hate you less
*(B+*(C+(*i))) //is the same as
B[C[*i]]
Since you're using C++ anyway, why not simplify the code (dramatically) by using std::vector instead of dynamically allocated arrays (and leaking one in the process)?
std::vector<int>countSort(int* start, int* end, int maxvalue)
{
std::vector<int> B(end-start);
std::vector<int> C(maxvalue);
for (int *i = start; i < end; i++)
++C[*i];
// etc.
Other than that, the logic you're using doesn't make sense to me. I think to get a working result, you're probably best off sitting down with a sheet of paper and working out the steps you need to use. I've left the counting part in place above, because I believe that much is correct. I don't think the rest really is. I'll even give a rather simple hint: once you've done the counting, you can generate B (your result) based only on what you have in C -- you do not need to refer back to the original array at all. The easiest way to do it will normally use a nested loop. Also note that it's probably easier to reserve the space in B and use push_back to put the data in it, rather than setting its initial size.

Can I use break to exit multiple nested 'for' loops?

Is it possible to use the break function to exit several nested for loops?
If so, how would you go about doing this? Can you also control how many loops the break exits?
No, don't spoil it with a break. This is the last remaining stronghold for the use of goto.
AFAIK, C++ doesn't support naming loops, like Java and other languages do. You can use a goto, or create a flag value that you use. At the end of each loop check the flag value. If it is set to true, then you can break out of that iteration.
Just to add an explicit answer using lambdas:
for (int i = 0; i < n1; ++i) {
[&] {
for (int j = 0; j < n2; ++j) {
for (int k = 0; k < n3; ++k) {
return; // yay we're breaking out of 2 loops here
}
}
}();
}
Of course this pattern has a certain limitations and obviously C++11 only but I think it's quite useful.
Another approach to breaking out of a nested loop is to factor out both loops into a separate function, and return from that function when you want to exit.
Of course, this brings up the other argument of whether you should ever explicitly return from a function anywhere other than at the end.
break will exit only the innermost loop containing it.
You can use goto to break out of any number of loops.
Of course goto is often Considered Harmful.
is it proper to use the break function[...]?
Using break and goto can make it more difficult to reason about the correctness of a program. See here for a discussion on this: Dijkstra was not insane.
How about this?
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
//Some statement
if (condition)
{
j=50;
k=50;
}
}
}
}
Although this answear was already presented, i think a good approach is to do the following:
for(unsigned int z = 0; z < z_max; z++)
{
bool gotoMainLoop = false;
for(unsigned int y = 0; y < y_max && !gotoMainLoop; y++)
{
for(unsigned int x = 0; x < x_max && !gotoMainLoop; x++)
{
//do your stuff
if(condition)
gotoMainLoop = true;
}
}
}
A code example using goto and a label to break out of a nested loop:
for (;;)
for (;;)
goto theEnd;
theEnd:
One nice way to break out of several nested loops is to refactor your code into a function:
void foo()
{
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
// If condition is true
return;
}
}
}
}
I know this is an old thread but I feel this really needs saying and don't have anywhere else to say it. For everybody here, use goto. I just used it.
Like almost everything, goto is not 100% either/xor "bad" or "good". There are at least two uses where I'd say that if you use a goto for them - and don't use it for anything else - you should not only be 100% okay, but your program will be even more readable than without it, as it makes your intention that much clearer (there are ways to avoid it, but I've found all of them to be much clunkier):
Breaking out of nested loops, and
Error handling (i.e. to jump to a cleanup routine at the end of a function in order to return a failure code and deallocate memory.).
Instead of just dogmatically accepting rules like "so-so is 'evil'", understand why that sentiment is claimed, and follow the "why", not the letter of the sentiment. Not knowing this got me in a lot of trouble, too, to the point I'd say calling things dogmatically "evil" can be more harmful than the thing itself. At worst, you just get bad code - and then you know you weren't using it right so long as you heard to be wary, but if you are wracking yourself trying to satisfy the dogmatism, I'd say that's worse.
Why "goto" is called "evil" is because you should never use it to replace ordinary ifs, fors, and whiles. And why that? Try it, try using "goto" instead of ordinary control logic statements, all the time, then try writing the same code again with the control logic, and tell me which one looks nicer and more understandable, and which one looks more like a mess. There you go. (Bonus: try and add a new feature now to the goto-only code.) That's why it's "evil", with suitable scope qualification around the "evil". Using it to short-circuit the shortcomings of C's "break" command is not a problematic usage, so long as you make it clear from the code what your goto is supposed to accomplish (e.g. using a label like "nestedBreak" or something). Breaking out of a nested loop is very natural.
(Or to put it more simply: Use goto to break out of the loop. I'd say that's even preferable. Don't use goto to create the loop. That's "evil".)
And how do you know if you're being dogmatic? If following an "xyz is evil" rule leads your code to be less understandable because you're contorting yourself trying to get around it (such as by adding extra conditionals on each loop, or some flag variable, or some other trick like that), then you're quite likely being dogmatic.
There's no substitute for learning good thinking habits, moreso than good coding habits. The former are prior to the latter and the latter will often follow once the former are adopted. The problem is, however, that far too often I find, the latter are not explicated enough. Too many simply say "this is bad" and "this needs more thought" without saying what to think, what to think about, and why. And that's a big shame.
(FWIW, in C++, the need to break out of nested loops still exists, but the need for error codes does not: in that case, always use exceptions to handle error codes, never return them unless it's going to be so frequent that the exception throw and catch will be causing a performance problem, e.g. in a tight loop in a high demand server code, perhaps [some may say that 'exceptions' should be 'used rarely' but that's another part of ill-thought-out dogmatism: no, at least in my experience after bucking that dogma I find they make things much clearer - just don't abuse them to do something other than error handling, like using them as control flow; effectively the same as with "goto". If you use them all and only for error handling, that's what they're there for.].)
goto can be very helpful for breaking nested loops
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
for (k = 0; k < 1000; k++) {
for (l = 0; l < 1000; l++){
....
if (condition)
goto break_me_here;
....
}
}
}
}
break_me_here:
// Statements to be executed after code breaks at if condition
I'm not sure if it's worth it, but you can emulate Java's named loops with a few simple macros:
#define LOOP_NAME(name) \
if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
{ \
[[maybe_unused]] CAT(_namedloop_break_,name): break; \
[[maybe_unused]] CAT(_namedloop_continue_,name): continue; \
} \
else
#define BREAK(name) goto CAT(_namedloop_break_,name)
#define CONTINUE(name) goto CAT(_namedloop_continue_,name)
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
Example usage:
#include <iostream>
int main()
{
// Prints:
// 0 0
// 0 1
// 0 2
// 1 0
// 1 1
for (int i = 0; i < 3; i++) LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << i << ' ' << j << '\n';
if (i == 1 && j == 1)
BREAK(foo);
}
}
}
Another example:
#include <iostream>
int main()
{
// Prints:
// 0
// 1
// 0
// 1
// 0
// 1
int count = 3;
do LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << ' ' << j << '\n';
if (j == 1)
CONTINUE(foo);
}
}
while(count-- > 1);
}
The break statement terminates the execution of the nearest enclosing do, for, switch, or while statement in which it appears. Control passes to the statement that follows the terminated statement.
from msdn.
I do think a goto is valid in this circumstance:
To simulate a break/continue, you'd want:
Break
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
goto theEnd;
}
}
}
theEnd:
Continue
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
i++;
goto multiCont;
}
}
multiCont:
}
Break any number of loops by just one bool variable see below :
bool check = true;
for (unsigned int i = 0; i < 50; i++)
{
for (unsigned int j = 0; j < 50; j++)
{
for (unsigned int k = 0; k < 50; k++)
{
//Some statement
if (condition)
{
check = false;
break;
}
}
if (!check)
{
break;
}
}
if (!check)
{
break;
}
}
In this code we break; all the loops.
Other languages such as PHP accept a parameter for break (i.e. break 2;) to specify the amount of nested loop levels you want to break out of, C++ however doesn't. You will have to work it out by using a boolean that you set to false prior to the loop, set to true in the loop if you want to break, plus a conditional break after the nested loop, checking if the boolean was set to true and break if yes.
I know this is old post . But I would suggest a bit logical and simpler answer.
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < conditionj; j++)
{
for(unsigned int k=0; k< conditionk ; k++)
{
// If condition is true
j= conditionj;
break;
}
}
}
bool found = false;
for(int i=0; i < m; ++i){
for(int j=0; j < n; ++j)
if(grid[i][j] == '*'){
q.push(make_pair(i,j));
found = true;
break;
}
if(found)
break;
}
My suggestion is use a check variable to break a desired loop. The result code may not be so pleasant.
You can use preprocessors in order to make desired breaking under the hood. This approach can hides ugly codes and extra complexity.
For example, I created my custom break mechanism as follow:
Wanted code:
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
for (int k = 0; k < 100; k++) {
//do something
if (desiredCondition) {
breakToLevel = 0;
}
if (breakToLevel < 3) {
break;
}
}
if (breakToLevel < 2) {
break;
}
}
if (breakToLevel < 1) {
break;
}
}
Defined macros:
#define BREAK_TO(L) breakToLevel = (L);
#define CHECK_BREAK(L) if (breakToLevel < (L)) break;
and result:
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
for (int k = 0; k < 100; k++) {
//do something
if (desiredCondition) {
BREAK_TO(0)
}
CHECK_BREAK(3)
}
CHECK_BREAK(2)
}
CHECK_BREAK(1)
}
while (i<n) {
bool shouldBreakOuter = false;
for (int j=i + 1; j<n; ++j) {
if (someCondition) {
shouldBreakOuter = true;
}
}
if (shouldBreakOuter == true)
break;
}
you can use "goto" to leave nested loops
below is my original code including "goto"
int main()
{
string str;
while (cin >> str)
{
if (str == "0")
break;
int sum = 0;
for (auto ch : str)
{
if (ch <= 'z' && ch >= 'a')
sum += (ch - 'a' + 1);
else if (ch >= 'A' && ch <= 'Z')
sum += (ch - 'A' + 1);
else
{
cout << "Fail" << endl;
goto fail;
}
}
cout << sum << endl;
fail:
}
return 0;
}
however, I could avoid "goto" by adding a function "calculate"
void calculate(const string &str)
{
int sum = 0;
for (auto ch : str)
{
if (ch <= 'z' && ch >= 'a')
sum += (ch - 'a' + 1);
else if (ch >= 'A' && ch <= 'Z')
sum += (ch - 'A' + 1);
else
{
cout << "Fail" << endl;
return;
}
}
cout << sum << endl;
}
int main()
{
string str;
while (cin >> str)
{
if (str == "0")
break;
calculate(str);
}
return 0;
}
You can use try...catch.
try {
for(int i=0; i<10; ++i) {
for(int j=0; j<10; ++j) {
if(i*j == 42)
throw 0; // this is something like "break 2"
}
}
}
catch(int e) {} // just do nothing
// just continue with other code
If you have to break out of several loops at once, it is often an exception anyways.
Breaking out of a for-loop is a little strange to me, since the semantics of a for-loop typically indicate that it will execute a specified number of times. However, it's not bad in all cases; if you're searching for something in a collection and want to break after you find it, it's useful. Breaking out of nested loops, however, isn't possible in C++; it is in other languages through the use of a labeled break. You can use a label and a goto, but that might give you heartburn at night..? Seems like the best option though.