使用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提供了语法一致性和一些标准库目前没有的扩展功能。
使用BOOST BIND库提高C++程序性能的更多相关文章
- 一个用于每一天JavaScript示例-使用缓存计算(memoization)为了提高应用程序性能
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- 提高WPF程序性能的几条建议
这篇博客将介绍一些提高WPF程序的建议(水平有限,如果建议有误,请指正.) 1. 加快WPF程序的启动速度: (1).减少需要显示的元素数量,去除不需要或者冗余的XAML元素代码. (2).使用UI虚 ...
- 用 Function.apply() 的参数数组化来提高 JavaScript程序性能
我们再来聊聊Function.apply() 在提升程序性能方面的技巧. 我们先从 Math.max() 函数说起, Math.max后面可以接任意个参数,最后返回所有参数中的最大值. 比如 aler ...
- 提高.net程序性能和稳定性-CLR Profile
CLR Profile能够看到应用程序的内存堆栈情况并且能够查询垃圾回收机制的行为.利用CLR Profile可以确定你的代码哪儿分配了太多内存,从而导致垃圾回收机制的执行,哪些代码长时间的占有内存. ...
- asp.net提高程序性能的技巧(一)
[摘 要] 我只是提供我几个我认为有助于提高写高性能的asp.net应用程序的技巧,本文提到的提高asp.net性能的技巧只是一个起步,更多的信息请参考<Improving ASP.NET Pe ...
- 提高ASP.NET应用程序性能的十大方法
一.返回多个数据集 检查你的访问数据库的代码,看是否存在着要返回多次的请求.每次往返降低了你的应用程序的每秒能够响应请求的次数.通过在单个数据库请求中返回多个结果集,可以减少与数据库通信的时间,使你的 ...
- 【翻译】七个习惯提高Python程序的性能
原文链接:https://www.tutorialdocs.com/article/7-habits-to-improve-python-programs.html 掌握一些技巧,可尽量提高Pytho ...
- iOS 程序性能优化
前言 转载自:http://www.samirchen.com/ios-performance-optimization/ 程序性能优化不应该是一件放在功能完成之后的事,对性能的概念应该从我们一开始写 ...
- 跨多种环境部署 Gearman -改善应用程序性能和降低服务器负载
您可能想要将工作扩散到一个大型机器群体中,或者想要在不同语言和环境之间共享功能,那么开放源码的 Gearman 服务可以让您轻松地将工作分布到网络中的其他机器.本文将介绍 Gearman 的一些典型应 ...
随机推荐
- A Simple problem
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2497 题意:给出顶点数,边数及节点s,判断s是 ...
- 【转】 java中HashMap详解
原文网址:http://blog.csdn.net/caihaijiang/article/details/6280251 java中HashMap详解 HashMap 和 HashSet 是 Jav ...
- 字符串(后缀自动机):Codeforces Round #129 (Div. 1) E.Little Elephant and Strings
E. Little Elephant and Strings time limit per test 3 seconds memory limit per test 256 megabytes inp ...
- 杂题 UVAoj 107 The Cat in the Hat
The Cat in the Hat Background (An homage to Theodore Seuss Geisel) The Cat in the Hat is a nasty c ...
- FFT(快速傅立叶变换):HDU 1402 A * B Problem Plus
Calculate A * B. Input Each line will contain two integers A and B. Process to end of file. Note: th ...
- C#控制台程序中处理2个关闭事件的代码实例
我们开发的控制台应用,在运行阶段很有可能被用户Ctrl+C终止或是被用户直接关闭.如果我们不希望用户通过Ctrl+C终止我们的程序,就需要对Ctrl+C或关闭事件作处理. 处理方法 在.net平台下C ...
- Binary Tree Inorder Traversal ——LeetCode
Given a binary tree, return the inorder traversal of its nodes' values. For example:Given binary tre ...
- CCASS四种交收指令
CCASS 提供了4种类型的指令:ATI: Account Transfer Instruction 账户转移指令,用于本券商各个仓位上的转移STI: Stock Segregate Account ...
- struts2入门程序
struts2入门程序 1.示例 搭建编程环境就先不说了,这里假设已经搭建好了编程环境,并且下好了strut2的jar包,接下来程序. 1.1 新建web项目 点击File->New->D ...
- PHP安全编程:跨站脚本攻击的防御(转)
跨站脚本攻击是众所周知的攻击方式之一.所有平台上的Web应用都深受其扰,PHP应用也不例外. 所有有输入的应用都面临着风险.Webmail,论坛,留言本,甚至是Blog.事实上,大多数Web应用提供输 ...