zoukankan      html  css  js  c++  java
  • 使用BOOST BIND库提高C++程序性能

      Boost.Bind为函数和函数对象,值语义和指针提供语义了一致的语法。我们首先通过一些简单的例子来看看它的基本用法,之后我们会延伸到嵌套绑定以实现功能组合。理解bind用法的一个关键是理解占位符(placeholder)的概念。占位符表示该参数将在函数对象里面提供。Boost.Bind提供多达9个这样的参数--_1, _2, _3, _4, _5,_6,_7,_8, _9.你可以在想要加入参数的地方使用它们。在第一个示例程序中,我们定义一个函数"nine_arguments",之后用bind表达式调用它。
      #include <IOSTREAM>
      #include boost/bind.hpp
      void nine_arguments(
      int i1,int i2,int i3,int i4,
      int i5,int i6,int i7,int i8, int i9) {
      std::cout 《 i1 《 i2 《 i3 《 i4 《 i5
      《 i6 《 i7 《 i8 《 i9 《 '
      ';
      }
      int main() {
      int i1=1,i2=2,i3=3,i4=4,i5=5,i6=6,i7=7,i8=8,i9=9;
      (boost::bind(&nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7))
      (i1,i2,i3,i4,i5,i6,i7,i8,i9);
      }</IOSTREAM>
      在这个程序中,你可以创建临时的匿名绑定器并且立即传参调用。如你所见,占位符的顺序是在本例中是混乱的,这使得参数的顺序也被打乱。另外,占位符可以在表达式中重复使用。示例程序1的输出是 www.lefeng123.com
      921638457
      占位符的序数与参数的位置是对应的,也就是说,_1被换为第一个参数,_2被换为第二个参数,以此类推。
      #include <IOSTREAM>
      #include <BOOST bind.hpp="">
      void PlaceholderTest(int a, int b, int c)
      {
      std::cout 《 a 《 b 《 c 《 std::endl;
      }
      int main()
      {
      int a = 1, b = 2, c = 3;
      //(boost::bind(&PlaceholderTest, _1, _2))(a, b); //error
      //(boost::bind(&PlaceholderTest, _1, _2, _1, _3))(a, b, c); //error
      //(boost::bind(&PlaceholderTest, _1, _2, _3))(a, b); //error
      (boost::bind(&PlaceholderTest, _1, _2, _1))(a, b); //OK,output:121
      (boost::bind(&PlaceholderTest, 99, _2, _1))(a, b) //OK,output:9921
      } </BOOST></IOSTREAM>
      总结 www.jamo123.com
      1、参数占位符数量与函数形参数量必须一致
      2、占位符的替代值可以少于占位符数量
      3、占位符和实参可以混合使用
      翻译:调用成员函数(1)
      我们看看如何使用bind调用类的成员函数。首先我们也从一个可以由标准库完成的操作开始,这样方便我们对比标准库调用和Boost.Bind调用。当我们在标准库容器类类型中存储元素时,通常需要对部分或所有元素调用成员函数。通常的实现方法是,将这些操作可以放在一个循环中。但是现在有更好的解决办法。观察如下的简单类--status.我们之后将用它来展示Boost.Bind的简单易用和强大之处。
      class status {
      std::string name_;
      bool ok_;
      public:
      status(const std::string& name):name_(name),ok_(true) {}
      void break_it() {
      ok_=false;
      }
      bool is_broken() const {
      return ok_;
      }
      void report() const {
      std::cout 《 name_ 《 is 《
      (ok_ ? working nominally:terribly broken) 《 '
      ';
      }
      };
      如果我们将这个类的实例储存在vector中,当我们需要调用成员函数report时,大概要遵循以下步骤
      std::vector<STATUS> statuses;
      statuses.push_back(status(status 1));
      statuses.push_back(status(status 2));
      statuses.push_back(status(status 3));
      statuses.push_back(status(status 4));
      statuses[1].break_it();
      statuses[2].break_it();
      for (std::vector<STATUS>::iterator it=statuses.begin();
      it!=statuses.end();++it) {
      it->report();
      }</STATUS></STATUS>
      for循环能够正确完成操作,但是它冗长、低效(每次都要检查statuses.end()),还不如使用标准库中专为这种操作设计的for_each算法来的清楚。为了使用for_each替代for循环,我们需要为vector元素调用成员函数report配置一个适配器。在这个实例中,由于元素是值存储的,我们需要的是mem_fun_ref适配器 www.yztrans.com
      std::for_each(
      statuses.begin(),
      statuses.end(),
      std::mem_fun_ref(&status::report));
      这是一种更好的办法--它是如此简洁,不会对代码的作用产生任何迷惑和误解。Boost.Bind中的等效代码如下:
      std::for_each(
      statuses.begin(),
      statuses.end(),
      boost::bind(&status::report,_1));
      bind版本仍然清晰明了。这是我们第一次真正使用上面提及的Bind库占位符,它向编译器和代码阅读者传递了这样一个信息,_1将在调用绑定器的函数中被实参替换。尽管这段代码长度减少了,但在本例中,它与使用标准库mem_fun_ref几乎没有差别。
      #include <IOSTREAM>
      #include <STRING>
      #include <VECTOR>
      #include
      #include <BOOST bind.hpp="">
      class Status
      {
      public:
      Status(const std::string &name) : name_(name), ok_(true){}
      void BreakIt()
      {
      ok_ = false;
      }
      bool IsBroken() const
      {
      return ok_;
      }
      void Report() const
      {
      std::cout 《 name_ 《 is 《 (ok_ ? ok : broken) 《 std::endl;
      }
      private:
      std::string name_;
      bool ok_;
      };
      int main()
      {
      std::vector<STATUS> v_status;
      v_status.push_back(Status(status 1));
      v_status.push_back(Status(status 2));
      v_status.push_back(Status(status 3));
      v_status.push_back(Status(status 4));
      v_status[1].BreakIt();
      v_status[2].BreakIt();
      std::cout 《 use or: 《 std::endl;
      for (std::vector<STATUS>::iterator it = v_status.begin(); it < v_status.end(); it++)
      {
      it->Report();
      }
      std::cout 《
      use or_each, mem_fun_ref: 《 std::endl;
      std::for_each(v_status.begin(), v_status.end(), std::mem_fun_ref(&Status::Report));
      std::cout 《
      use or_each, bind: 《 std::endl;
      //std::for_each(v_status.begin(), v_status.end(), boost::bind(&Status::Report)); //error
      std::for_each(v_status.begin(), v_status.end(), boost::bind(&Status::Report, _1));
      }</STATUS></STATUS></BOOST></ALGORITHM></VECTOR></STRING></IOSTREAM>
      总结:
      bind成员函数最大的不同是,必须指明调用该函数的实例对象,代码中用"_1"表示。
      翻译:调用成员函数(2)
      下面,我们稍微改造一下vector容器,让它装入指针而不是值:
      std::vector<STATUS*> p_statuses;
      p_statuses.push_back(new status(status 1));
      p_statuses.push_back(new status(status 2));
      p_statuses.push_back(new status(status 3));
      p_statuses.push_back(new status(status 4));
      p_statuses[1]->break_it();
      p_statuses[2]->break_it();</STATUS*>
      我们仍然可以用两种标准库,但是我们不能用mem_fun_ref,而是用mem_fun适配器,虽然它的名字听起来有点儿混淆,完成操作还是没问题的。
      std::for_each(
      p_statuses.begin(),
      p_statuses.end(),
      std::mem_fun(&status::report));
      注意到,这段代码的语法已经有所改变,尽管我们要做的工作几乎相同。当然,如果代码的语法和上面的例子一样就最好了,这样我们就可以更多地关注代码到底做了些什么而不是它怎么做的。使用Bind,我们不需要显式指明要处理的元素是指针(这在容器类型中已经说明了,重复的信息在现代的库里面显然是不必要的)
      std::for_each(
      p_statuses.begin(),
      p_statuses.end(),
      boost::bind(&status::report,_1));
      如你所见,这与之前非指针元素的代码没有任何区别。也就是说如果你理解了刚才的bind,那么这个也能理解。
      #include <IOSTREAM>
      #include <STRING>
      #include <VECTOR>
      #include
      #include <BOOST bind.hpp="">
      class Status
      {
      public:
      Status(const std::string &name) : name_(name), ok_(true){}
      void BreakIt()
      {
      ok_ = false;
      }
      bool IsBroken() const
      {
      return ok_;
      }
      void Report() const
      {
      std::cout 《 name_ 《 is 《 (ok_ ? ok : broken) 《 std::endl;
      }
      private:
      std::string name_;
      bool ok_;
      };
      int main()
      {
      std::vector<STATUS*> v_pstatus;
      v_pstatus.push_back(new Status(status 1));
      v_pstatus.push_back(new Status(status 2));
      v_pstatus.push_back(new Status(status 3));
      v_pstatus.push_back(new Status(status 4));
      v_pstatus[1]->BreakIt();
      v_pstatus[2]->BreakIt();
      std::cout 《 use or: 《 std::endl;
      for (std::vector<STATUS*>::iterator it = v_pstatus.begin(); it < v_pstatus.end(); it++)
      {
      (*it)->Report();
      }
      std::cout 《
      use or_each, mem_fun_ref: 《 std::endl;
      std::for_each(v_pstatus.begin(), v_pstatus.end(), std::mem_fun(&Status::Report));
      std::cout 《
      use or_each, bind: 《 std::endl;
      std::for_each(v_pstatus.begin(), v_pstatus.end(), boost::bind(&Status::Report, _1));
      }</STATUS*></STATUS*></BOOST></ALGORITHM></VECTOR></STRING></IOSTREAM>
      总结:
      只有bind保持了形式不变
      翻译:调用成员函数(3)
      我们决定使用指针后,有另外一个问题,即指针的生命周期控制。我们必须手动释放p_statuses中的元素,这很容易出错而且没有必要。因此,我们可能选择使用智能指针(smart pointers),代码变化如下:
      std::vector<BOOST::SHARED_PTR<STATUS> > s_statuses;
      s_statuses.push_back(
      boost::shared_ptr<STATUS>(new status(status 1)));
      s_statuses.push_back(
      boost::shared_ptr<STATUS>(new status(status 2)));
      s_statuses.push_back(
      boost::shared_ptr<STATUS>(new status(status 3)));
      s_statuses.push_back(
      boost::shared_ptr<STATUS>(new status(status 4)));
      s_statuses[1]->break_it();
      s_statuses[2]->break_it();</STATUS></STATUS></STATUS></STATUS></BOOST::SHARED_PTR<STATUS>
      现在,我们该使用标准库中的哪个适配器了?由于智能指针并没有report成员函数,mem_fun和mem_fun_ref都不能用了。如下代码会编译失败。
      std::for_each(
      s_statuses.begin(),
      s_statuses.end(),
      std::mem_fun(&status::report));
      我们的好运用完了,标准库并不能帮我们完成这个任务。因此,我们只能借助于之前想避开的for形式或者……Boost.Bind,它可以完全正确地完成任务。
      std::for_each(
      s_statuses.begin(),
      s_statuses.end(),
      boost::bind(&status::report,_1));
      这与前面的代码是完全一样的(除了容器的名字)。同样的语法可以用于绑定值语义、指针语义或者只能指针。有时候,不同的语法可以帮助我们理解代码,但在我们讨论的情况中不是这样--我们手中的任务是在容器的元素上调用成员函数,没有其他的需求。语法一致的价值是不容轻视的,它既帮助了写代码的人,也帮助了以后维护代码的人。(当然,实际上我们没有写需要维护的代码,但出于参数的考虑,让我们假装是这样做的吧^_^)。
      #include <IOSTREAM>
      #include <STRING>
      #include <VECTOR>
      #include
      #include <BOOST bind.hpp="">
      #include <BOOST shared_ptr.hpp="">
      class Status
      {
      public:
      Status(const std::string &name) : name_(name), ok_(true){}
      void BreakIt()
      {
      ok_ = false;
      }
      bool IsBroken() const
      {
      return ok_;
      }
      void Report() const
      {
      std::cout 《 name_ 《 is 《 (ok_ ? ok : broken) 《 std::endl;
      }
      private:
      std::string name_;
      bool ok_;
      };
      int main()
      {
      std::vector< boost::shared_ptr<STATUS> > v_spstatus;
      v_spstatus.push_back(boost::shared_ptr<STATUS>(new Status(status 1)));
      v_spstatus.push_back(boost::shared_ptr<STATUS>(new Status(status 2)));
      v_spstatus.push_back(boost::shared_ptr<STATUS>(new Status(status 3)));
      v_spstatus.push_back(boost::shared_ptr<STATUS>(new Status(status 4)));
      v_spstatus[1]->BreakIt();
      v_spstatus[2]->BreakIt();
      //std::cout 《 use or: 《 std::endl;
      //for (std::vector<STATUS*>::iterator it = v_spstatus.begin(); it < v_spstatus.end(); it++)
      //{
      // (*it)->Report();
      //}
      //std::cout 《
      use or_each, mem_fun_ref: 《 std::endl;
      //std::for_each(v_spstatus.begin(), v_spstatus.end(), std::mem_fun(&Status::Report));
      std::cout 《
      use or_each, bind: 《 std::endl;
      std::for_each(v_spstatus.begin(), v_spstatus.end(), boost::bind(&Status::Report, _1));
      }</STATUS*></STATUS></STATUS></STATUS></STATUS></STATUS></BOOST>
      </BOOST></ALGORITHM></VECTOR></STRING></IOSTREAM>
      总结:
      1、标准库中的方法不再能够使用
      2、使用share_ptr必须引入头文件#include
      这些例子展示了一些Boost.Bind最基本最常用的情况,也是它最擅长的方面。尽管标准库也提供了一些基本工具让我们完成同样的任务,但我们看到Bind提供了语法一致性和一些标准库目前没有的扩展功能。

  • 相关阅读:
    CS224n, lec 10, NMT & Seq2Seq Attn
    CS231n笔记 Lecture 11, Detection and Segmentation
    CS231n笔记 Lecture 10, Recurrent Neural Networks
    CS231n笔记 Lecture 9, CNN Architectures
    CS231n笔记 Lecture 8, Deep Learning Software
    CS231n笔记 Lecture 7, Training Neural Networks, Part 2
    pytorch坑点排雷
    Sorry, Ubuntu 17.10 has experienced an internal error
    VSCode配置python插件
    tmux配置与使用
  • 原文地址:https://www.cnblogs.com/haosola/p/3640025.html
Copyright © 2011-2022 走看看