Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Don't understand this block of code(it runs with no condition)

Tags:

c++

I'm learning c++ and haven't really seen this in any of the books I've read. I wanted to read and comment code so I can learn better and came across a odd section of code that runs but does not have a condition. From what I read(and my experiences with other languages, you need an if, while,for or something for blocks).

I'm looking at the tbb threads package so I'm not sure if its related to launching threads or c++ specific(if you don't recognize this as something common in c++ then its probably tdd specific).

I think I understand what the code inside actually does but I'm not sure how its being triggered or ran. Any ideas?

Here's the section:

    {
        //this is the graph part of the code
        Graph g;
        g.create_random_dag(nodes);
        std::vector<Cell*> root_set;
        g.get_root_set(root_set);
        root_set_size = root_set.size();
        for( unsigned int trial=0; trial<traversals; ++trial ) {
            ParallelPreorderTraversal(root_set);
        }
    }

p.s. If it helps here's the entire file(the above code is in the middle of the main()).

#include <cstdlib>
#include "tbb/task_scheduler_init.h"
#include "tbb/tick_count.h"
#include "../../common/utility/utility.h"
#include <iostream>
#include <vector>
#include "Graph.h"

// some forward declarations
class Cell;
void ParallelPreorderTraversal( const std::vector<Cell*>& root_set );

//------------------------------------------------------------------------
// Test driver
//------------------------------------------------------------------------
utility::thread_number_range threads(tbb::task_scheduler_init::default_num_threads);
static unsigned nodes = 1000;
static unsigned traversals = 500;
static bool SilentFlag = false;

//! Parse the command line.
static void ParseCommandLine( int argc, const char* argv[] ) {
    utility::parse_cli_arguments(
            argc,argv,
            utility::cli_argument_pack()
                //"-h" option for for displaying help is present implicitly
                .positional_arg(threads,"n-of-threads","number of threads to use; a range of the form low[:high], where low and optional high are non-negative integers or 'auto' for the TBB default.")
                .positional_arg(nodes,"n-of-nodes","number of nodes in the graph.")
                .positional_arg(traversals,"n-of-traversals","number of times to evaluate the graph. Reduce it (e.g. to 100) to shorten example run time\n")
                .arg(SilentFlag,"silent","no output except elapsed time ")
    );
}

int main( int argc, const char* argv[] ) {
    try {
        tbb::tick_count main_start = tbb::tick_count::now(); //tbb counter start
        ParseCommandLine(argc,argv);

        // Start scheduler with given number of threads.
        std::cout << threads << std::endl;
        for( int p=threads.first; p<=threads.last; ++p ) {
            tbb::tick_count t0 = tbb::tick_count::now(); //timer
            tbb::task_scheduler_init init(4); //creates P number of threads
            srand(2); //generates a random number between 0-2?
            size_t root_set_size = 0; 
            {
                //this is the graph part of the code
                Graph g;
                g.create_random_dag(nodes);
                std::vector<Cell*> root_set;
                g.get_root_set(root_set);
                root_set_size = root_set.size();
                for( unsigned int trial=0; trial<traversals; ++trial ) {
                    ParallelPreorderTraversal(root_set);
                }
            }
            tbb::tick_count::interval_t interval = tbb::tick_count::now()-t0; //counter done
            if (!SilentFlag){ //output the results
                std::cout
                    <<interval.seconds()<<" seconds using "<<p<<" threads ("<<root_set_size<<" nodes in root_set)\n";
            }
        }
        utility::report_elapsed_time((tbb::tick_count::now()-main_start).seconds());

        return 0;
    }catch(std::exception& e){
        std::cerr
            << "unexpected error occurred. \n"
            << "error description: "<<e.what()<<std::endl;
        return -1;
    }
}
like image 507
Lostsoul Avatar asked May 15 '12 01:05

Lostsoul


2 Answers

No you don't need an if or while statement to introduce a new level of scope. Basically the { symbol opens a new scope level and } ends it. The usual scoping rules apply, for example, variables defined within this new block are undefined outside of, at the end of the block object destructors are run, and variables named the same as another in a scope level above will be shadowed.

A common use case is in switch statements. For example,

switch (a)
{
    case 1:
    {
        int i;
    }
    case 2:
    {
        int i; //note reuse of variable with the same name as in case 1
    }
}

Without the { } in the case statements the compiler will complain about multiply defined identifiers.

like image 199
sashang Avatar answered Oct 31 '22 04:10

sashang


The pair of { and } are creating a local scope. At the end of the scope the compiler will automatically invoke destructors for all stack variables (if one exists) that were declared within that scope.

In your case, destructors for g and root_set will be called at the end of the scope.

One very common use I can think of is to obtain a mutex lock when working with threads. Let's say you have a class named Lock that accepts a mutex object and acquires a lock on it. Then you can surround a critical section of code that needs to be protected from concurrent access as follows:

{
  Lock lock( mutex );   // the Lock constructor will acquire a lock on mutex

  // do stuff
} // Here the Lock destructor runs and releases the lock on mutex, allowing
  // other threads to acquire a lock

The advantage of doing the above is that even if the code within the { ... } block throws an exception, the compiler still invokes Lock's destructor ensuring that the mutex lock is released.

like image 42
Praetorian Avatar answered Oct 31 '22 03:10

Praetorian