7

我正在学习 c++ 并且在我读过的任何书中都没有真正看到这一点。我想阅读和评论代码,以便我可以更好地学习,并遇到了一段运行但没有条件的奇怪代码。根据我阅读的内容(以及我对其他语言的经验,您需要一个 if、while、for 或其他块)。

我正在查看 tbb 线程包,所以我不确定它是否与启动线程或 c++ 特定相关(如果你不认为这是 c++ 中常见的东西,那么它可能是 tdd 特定的)。

我想我理解里面的代码实际上做了什么,但我不确定它是如何被触发或运行的。有任何想法吗?

这是该部分:

    {
        //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);
        }
    }

ps 如果有帮助,这里是整个文件(上面的代码在 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;
    }
}
4

4 回答 4

18

不,您不需要iforwhile语句来引入新的范围级别。基本上,{符号会打开一个新的范围级别并}结束它。通常的作用域规则适用,例如,在这个新块中定义的变量在外部未定义,在块的末尾运行对象析构函数,并且在上面的作用域级别中与另一个命名相同的变量将被隐藏。

一个常见的用例是在switch语句中。例如,

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

如果没有{ }in case 语句,编译器将抱怨多重定义的标识符。

于 2012-05-15T01:40:17.777 回答
7

这对{}正在创建一个本地范围。在作用域结束时,编译器将自动为在该作用域内声明的所有堆栈变量(如果存在)调用析构函数。

在您的情况下,析构函数groot_set将在范围结束时调用。

我能想到的一个非常常见的用途是在使用线程时获得互斥锁。假设您有一个名为的类,该类Lock接受一个互斥对象并获取它的锁。然后,您可以围绕需要防止并发访问的关键代码部分,如下所示:

{
  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

这样做的好处是即使{ ... }块内的代码抛出异常,编译器仍然会调用Lock的析构函数来确保互斥锁被释放。

于 2012-05-15T01:44:06.207 回答
4

如果您指的是代码块有一组额外的花括号,这在 C++ 编程中处理堆栈上的短期对象时并不少见,在这种情况下是Graphandstd::vector<Cell*>对象。一对花括号创建了一个新范围。它们不必附加到任何控制语句。因此,在这种情况下,使用临时作用域来确保Graphandvector对象在超出作用域时被快速释放。for如果不存在额外的大括号,则在外循环的下一次迭代之前不会释放对象。

于 2012-05-15T01:44:45.127 回答
2

你可以像这样创建额外的块。它们用于施加额外的范围。在您的示例中, G 在该块之前或之后将不存在。

于 2012-05-15T01:40:33.713 回答