2012-05-15 10 views
8

Estoy aprendiendo C++ y realmente no lo he visto en ninguno de los libros que he leído. Quería leer y comentar el código para poder aprender mejor y encontré una sección extraña de código que se ejecuta pero que no tiene una condición. Por lo que leí (y mis experiencias con otros idiomas, necesitas un if, while, for o algo para los bloques).No entiendo este bloque de código (funciona sin condición)

Estoy viendo el paquete thbb threads, así que no estoy seguro de si está relacionado con el lanzamiento de threads o C++ specific (si no reconoce esto como algo común en C++ entonces probablemente sea tdd).

Creo que entiendo lo que hace el código en realidad, pero no estoy seguro de cómo se desencadenó o ejecutó. ¿Algunas ideas?

Aquí está la sección:

{ 
     //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. Si ayuda, aquí está el archivo completo (el código anterior está en el medio de 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; 
    } 
} 
+0

http://en.wikibooks.org/wiki/C%2B%2B_Programming/Scope/Examples - específicamente la sección "// Scope Programme complicado" – WernerCD

Respuesta

18

No, no necesita una declaración if o while a introducir un nuevo nivel de alcance. Básicamente, el símbolo { abre un nuevo nivel de alcance y } lo finaliza. Se aplican las reglas habituales de determinación del alcance, por ejemplo, las variables definidas dentro de este nuevo bloque no están definidas fuera de, al final del bloque se ejecutan los destructores de objetos, y las variables nombradas igual que otro en un nivel de alcance anterior se sombrearán.

Un caso de uso común es en las declaraciones switch. Por ejemplo,

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

Sin la {} en los estados de casos el compilador se quejará de identificadores multiplican definidos.

+0

interesante ... gracias. Me pregunto ¿cuál es el uso de la vida real? ¿Es útil facilitar la limpieza (gratuita, etc.) o cuál es el objetivo? – Lostsoul

+3

Sí, se usa para un control más preciso del alcance de las variables locales, no solo desde dónde se puede acceder, sino también cuando se liberan si son objetos basados ​​en la pila. –

+2

También puede reutilizar los mismos nombres de variable si lo desea, pero el mismo en un exterior e interior no es tan útil como dos en ámbitos paralelos. – chris

2

Puede crear bloques adicionales como ese. Se utilizan para imponer un nivel de alcance adicional. En su ejemplo, G no existirá antes o después de ese bloque.

7

El par de { y } están creando un local scope. Al final del alcance, el compilador invocará automáticamente destructores para todas las variables de la pila (si existe) que se declararon dentro de ese alcance.

En su caso, se invocarán destructores para g y root_set al final del alcance.

Un uso muy común que se me ocurre es obtener un bloqueo de exclusión mutua cuando se trabaja con hilos. Supongamos que tiene una clase llamada Lock que acepta un objeto mutex y adquiere un bloqueo en él. A continuación, puede rodear una sección crítica de código que necesita ser protegido del acceso concurrente de la siguiente manera:

{ 
    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 

La ventaja de hacer lo anterior es que, incluso si el código del bloque { ... } lanza una excepción, el compilador todavía invoca el destructor Lock asegurando que se libera el bloqueo mutex.

4

Si se refiere al hecho de que el bloque de código tiene un par adicional de llaves, eso no es raro en la programación C++ cuando se trata de objetos efímeros en la pila, en este caso los objetos Graph y std::vector<Cell*>. Un par de llaves crea un nuevo alcance.No tienen que estar adjuntos a ninguna declaración de control. Entonces, en este caso, se usa un alcance temporal para asegurar que los objetos Graph y vector se liberen rápidamente cuando se salgan del alcance. Si los refuerzos extra no estuvieran presentes, los objetos no se liberarían hasta la siguiente iteración del ciclo for externo.

Cuestiones relacionadas