- 浏览: 512670 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
jkxydp:
算法运行的结果根本就不对。
BM算法. -
soarwindzhang:
感谢博主的分享,我今天看了您的UFSET非递归的路径压缩时感觉 ...
并查集 -
zhangning290:
楼主好像只考虑了坏字符规则,。没有考虑好后缀
BM算法. -
lsm0622:
文字描述有错误 误导新学者
求有向图的强连通分量(scc):Tarjan算法 -
knightchen:
博主,你太强了!这篇文章对我学习C++多线程很有帮助!谢谢
并发学习之一_windows下ZThread在CodeBlocks上的安装与配置
1,inline函数:看起来像函数,动作起来像函数,比宏好得多,不需要蒙受函数调用带来的额外负担.
而且,编译器最佳化机制通常用来浓缩那些不含函数调用动作的代码,所以当你inline一个函数时,编译器就有能力在函数体身上执行某种最佳化.
2,inline函数背后的观念:将对函数的每一个调用行为都用函数代码取代之.
显然这么做,会增加你目标代码的大小.
inline行为造成的程序代码膨胀可能会导致病态的换页,或是降低cache的命中率.
3,特别注意的是:
inline指令就像register指令一样,只是对编译器的一种提示,而不是强制命令.
大部分编译器会拒绝将复杂的函数(内含循环或递归)inline化,所有的虚拟函数都会阻止inline的进行.
这是因为virtual意味着"等待,直到运行时期再确定调用哪一个函数."
inline意味着"在编译阶段,将调用动作以被调用函数的本体取代之"
4,理论和实际在这个问题上很可能分道扬镳:
inline函数的定义几乎总是被放在头文件中.
举个例子:
// This is file example.h
inline void f() { ... } // definition of f
...
// This is file source1.cpp
#include "example.h" // includes definition of f
... // contains calls to f
// This is file source2.cpp
#include "example.h" // also includes definition of f
... // also calls f
假设f没有被inline,那么source1和source2目标文件中均含有f的函数,均未强化的,连接这两个模块时,就会造成连接错误.
因此,旧规则宣布"编译器对待一个inline失败的函数,犹如函数被声明为static似的".
由此可见,在旧的规则下,如果一个inline函数inline失败,你不仅必须在每次调用函数时付出函数调用的成本,还得承受代码体积增加的事实,因为每个调用f的编译单元都有它们自己的一份f函数吗,以及f中的每一个static变量.
5,有的情况,编译器必须为已经成功inline的函数产生一个函数体.
例如:你的程序曾经取一个inline函数的地址,编译器就必须为此函数产生一份函数实体.
如:
inline void f() {...} // as above
void (*pf)() = f; // pf points to f
int main()
{
f(); // an inline call to f
pf(); // a non-inline call to f
// through pf
...
}
注:新规则之下,不论牵扯的编译单元有几个,只有一个out-of-line的f副本被产生出来.
很多时候,编译器会为constructor和destructor等函数产生out-of-line副本,从而使自己可以获得这些函数的指针.
例如:
class Base {
public:
...private:
string bm1, bm2; // base members 1 and 2
};class Derived: public Base {
public:
Derived() {} // Derived's ctor is
... // empty -- or is it?
private:
string dm1, dm2, dm3; // derived members 1-3
};
因为C++有很多保证一定会发生的事情,如"产生一个对象时,其base对象和每个data members都会被自动构造".
这些事情一定不是凭空发生的,"如何发生"是编译器实现者的权限.编译器可能会将一些代码安插到某些地方.
事实上,constructor和destructor往往不是inline的最佳候选人.
例如:
// possible implementation of Derived constructor
Derived::Derived()
{
// allocate heap memory for this object if it's supposed
// to be on the heap; see Item 8 for info on operator new
if (this object is on the heap)
this = ::operator new(sizeof(Derived));
Base::Base(); // initialize Base part
dm1.string(); // construct dm1
dm2.string(); // construct dm2
dm3.string(); // construct dm3
}
这样一来Derived()的大小就增加了,注意string的构造函数也要增加,这样Derived将变得很大,是否将Derived()inline化,答案显而易见.
6,inline带来的另一个冲击:
inline函数无法随着程序的升级而升级.
因为一旦inline函数f被改变,所有用到f的程序都必须重新编译.
如果f不是inline,f被修改后,用户只需重新连接即可,远比重新编译的负担小.
7,inline函数中的static对象常会展现反直观的行为.
因此如果函数带有static对象,通常要避免将它声明为inline.
8,最重要的原因:大部分除错器对inline函数束手无策.
9,总结:该不该使用inline的策略
一开始,不要将任何函数声明为inline,或至少将inline范围限制在那些实在非常琐屑平凡的函数身上.
例如下面的age函数:
class Person {
public:
int age() const { return personAge; }
...
private:
int personAge;
...
};
根据80-20的经验法则,找出程序中占重要效率低位的函数,然后向办法将它们inline化.
而且,编译器最佳化机制通常用来浓缩那些不含函数调用动作的代码,所以当你inline一个函数时,编译器就有能力在函数体身上执行某种最佳化.
2,inline函数背后的观念:将对函数的每一个调用行为都用函数代码取代之.
显然这么做,会增加你目标代码的大小.
inline行为造成的程序代码膨胀可能会导致病态的换页,或是降低cache的命中率.
3,特别注意的是:
inline指令就像register指令一样,只是对编译器的一种提示,而不是强制命令.
大部分编译器会拒绝将复杂的函数(内含循环或递归)inline化,所有的虚拟函数都会阻止inline的进行.
这是因为virtual意味着"等待,直到运行时期再确定调用哪一个函数."
inline意味着"在编译阶段,将调用动作以被调用函数的本体取代之"
4,理论和实际在这个问题上很可能分道扬镳:
inline函数的定义几乎总是被放在头文件中.
举个例子:
// This is file example.h
inline void f() { ... } // definition of f
...
// This is file source1.cpp
#include "example.h" // includes definition of f
... // contains calls to f
// This is file source2.cpp
#include "example.h" // also includes definition of f
... // also calls f
假设f没有被inline,那么source1和source2目标文件中均含有f的函数,均未强化的,连接这两个模块时,就会造成连接错误.
因此,旧规则宣布"编译器对待一个inline失败的函数,犹如函数被声明为static似的".
由此可见,在旧的规则下,如果一个inline函数inline失败,你不仅必须在每次调用函数时付出函数调用的成本,还得承受代码体积增加的事实,因为每个调用f的编译单元都有它们自己的一份f函数吗,以及f中的每一个static变量.
5,有的情况,编译器必须为已经成功inline的函数产生一个函数体.
例如:你的程序曾经取一个inline函数的地址,编译器就必须为此函数产生一份函数实体.
如:
inline void f() {...} // as above
void (*pf)() = f; // pf points to f
int main()
{
f(); // an inline call to f
pf(); // a non-inline call to f
// through pf
...
}
注:新规则之下,不论牵扯的编译单元有几个,只有一个out-of-line的f副本被产生出来.
很多时候,编译器会为constructor和destructor等函数产生out-of-line副本,从而使自己可以获得这些函数的指针.
例如:
class Base {
public:
...private:
string bm1, bm2; // base members 1 and 2
};class Derived: public Base {
public:
Derived() {} // Derived's ctor is
... // empty -- or is it?
private:
string dm1, dm2, dm3; // derived members 1-3
};
因为C++有很多保证一定会发生的事情,如"产生一个对象时,其base对象和每个data members都会被自动构造".
这些事情一定不是凭空发生的,"如何发生"是编译器实现者的权限.编译器可能会将一些代码安插到某些地方.
事实上,constructor和destructor往往不是inline的最佳候选人.
例如:
// possible implementation of Derived constructor
Derived::Derived()
{
// allocate heap memory for this object if it's supposed
// to be on the heap; see Item 8 for info on operator new
if (this object is on the heap)
this = ::operator new(sizeof(Derived));
Base::Base(); // initialize Base part
dm1.string(); // construct dm1
dm2.string(); // construct dm2
dm3.string(); // construct dm3
}
这样一来Derived()的大小就增加了,注意string的构造函数也要增加,这样Derived将变得很大,是否将Derived()inline化,答案显而易见.
6,inline带来的另一个冲击:
inline函数无法随着程序的升级而升级.
因为一旦inline函数f被改变,所有用到f的程序都必须重新编译.
如果f不是inline,f被修改后,用户只需重新连接即可,远比重新编译的负担小.
7,inline函数中的static对象常会展现反直观的行为.
因此如果函数带有static对象,通常要避免将它声明为inline.
8,最重要的原因:大部分除错器对inline函数束手无策.
9,总结:该不该使用inline的策略
一开始,不要将任何函数声明为inline,或至少将inline范围限制在那些实在非常琐屑平凡的函数身上.
例如下面的age函数:
class Person {
public:
int age() const { return personAge; }
...
private:
int personAge;
...
};
根据80-20的经验法则,找出程序中占重要效率低位的函数,然后向办法将它们inline化.
发表评论
-
条款43:明智地使用多继承
2010-06-08 09:33 14461,多继承带来的一个根本性的复杂性:模棱两可. 例如: # ... -
条款44:说出你的意思并了解你所说的每一句话
2010-06-08 09:30 8191,彻底了解不同的面向对象架构在C++中的意义. 2,声明一 ... -
条款30:避免写出member function,传回一个non-const function或reference并指向private或protect成员
2010-06-08 09:29 12361,先看一个例子: class Address { ... } ... -
条款4:尽量使用C++风格的注释形式
2010-06-07 09:49 7651,抛弃"/*...*/",改用" ... -
条款39:避免在继承体系中做向下转型(downcast)动作
2010-06-01 10:37 14981,先看个例子: class Person { ... }; ... -
条款2:尽量以<iostream>取代<stdio.h>
2010-06-01 10:36 10211,scanf和printf的缺点:不具有型别安全(type- ... -
条款1:尽量以const和inline取代#define
2010-06-01 10:35 9641,意思就是"尽量以编译器(compiler)&qu ... -
条款42:明智地使用private inheritance(私有继承)
2010-05-29 17:51 10481,先搞清楚private inheritance的行为: ( ... -
条款41:区分inheritance和template
2010-05-29 17:50 7221,首先考虑一个问题: 型别T会影响class的行为吗? 如果 ... -
条款40:通过layering技术来模塑"有一个"(has-a)或"根据某物实现(is-implemented-in-terms-of)"
2010-05-29 17:48 8141,所谓laying,就是以一个class为本,建立另外一个c ... -
条款38:绝对不要重新定义继承而来的缺省参数值
2010-05-29 17:48 8211,首先可以安全的把问题讨论局限于"继承一个带有缺省 ... -
条款37:绝对不要重新定义继承而来的非虚拟函数
2010-05-29 17:47 7741,先看个例子: class B { public: vo ... -
条款36:区分接口继承和实现继承
2010-05-29 17:46 8911,public继承分为两类:接口继承和实现继承. 这两种继承 ... -
条款35:确定你的public继承,模塑出"isa"的关系
2010-05-29 17:46 10051,C++面向对象程序设计最重要的原则: public继承意味 ... -
条款29:避免传回内部数据的handles
2010-05-28 10:35 14261,考虑下面的代码: class string { oper ... -
条款28:尝试切割global namesapce
2010-05-28 10:34 7211,namesapce的使用 namespace std{ ... -
条款50:加强自己对C++的了解
2010-05-25 11:46 9011,只推荐两本书: (1)D&E: The Desig ... -
条款49:尽量让自己熟悉C++标准库
2010-05-25 11:46 8081,标准库的每一样东西几乎都在namespace std中,然 ... -
条款48:不要对编译器的警告视而不见
2010-05-25 11:45 8011,在你忽略一个警告之前,你必须精确了解编译器企图告诉你的是什 ... -
条款47:使用non-local static objects之前先确定它已有初值
2010-05-25 11:45 8671,当一个编译单元内某对象的初始化动作,与另一个编译单元内某对 ...
相关推荐
条款33: 明智地使用内联 条款34: 将文件间的编译依赖性降至最低 第六章 继承和面向对象设计 条款35: 使公有继承体现 "是一个" 的含义 条款36: 区分接口继承和实现继承 条款37: 决不要重新定义继承而来的非虚函数 ...
条款33:避免遮掩继承而来的名称 avoid hiding inherited names. 条款34:区分接口继承和实现继承 differentiate between inheritance of interface and inheritance of implementation. 条款35:考虑virtual函数...
条款33:避免遮掩继承而来的名称 条款34:区分接口继承和实现继承 条款35:考虚virtual函数以外的其他选择 条款36:绝不重新定义继承而来的non-virtual函数 条款37:绝不重新定义继承而来的缺省参数值 条款38:...
本篇文章将深入探讨`display:inline`、`display:block`以及`display:inline-block`这三种主要的显示模式之间的区别,帮助你更好地理解它们在实际开发中的应用。 首先,我们来看`display:inline`。这种模式使得元素...
主要给大家介绍了CSS中的display:flex和display:inline-flex属性,文中分别通过两段实例代码给大家介绍了display:flex和display:inline-flex的使用效果,感兴趣的朋友们可以参考借鉴,下面来一起看看吧。
在提供的压缩包文件 "display-block应用" 中,可能包含了使用 `display:inline-block` 进行布局的示例代码或教程,通过学习和实践这些案例,可以帮助你更好地理解和掌握这一技巧。 总之,`display:inline-block` 是...
C++是一种强大的、通用的编程语言,以其面向对象特性、高效性能和丰富的库支持而闻名。...因此,明智地选择何时使用`inline`是每个C++程序员应具备的技能。这个教程和源码将帮助你在这个过程中迈出坚实的一步。
**条款33:明智地使用内联** - **背景**:`inline`关键字用于指示编译器尝试内联函数调用。 - **原因**:过度使用`inline`可能会导致代码膨胀。 - **示例**: ```cpp inline int add(int a, int b) { return a +...
现代浏览器的最新版都支持inline-block,只有该死的ie6、7不支持inline-block,但ie6、7可以通过 display:inline;zoom:1;来模拟。 下面是inline-block兼容的代码: view sourceprint?display:inline-block;*...
同时,我们也了解了其他几种常见的`display`值及其用途,这对于更好地理解和运用CSS布局具有重要意义。 总之,在处理复杂的页面布局时,正确使用`display`属性可以极大地提高工作效率,帮助开发者快速构建出既美观...
综上所述,inline hook是一种强大的编程技术,能够灵活地改变程序的行为。然而,它也带来了一系列挑战,包括兼容性、安全性和调试难度等。在使用inline hook时,开发者需要充分了解其原理和潜在风险,才能有效且安全...
在网页布局设计中,`display:inline-block` 是一个非常常用且强大的CSS属性,它允许元素在保持块级元素特性的同时,像内联元素一样并排显示。然而,在不同浏览器之间,尤其是在Firefox(FF)上,可能会遇到一些显示...
内核三步走实现Inline Hook是一种在操作系统内核层面对函数进行动态拦截和修改的技术,常用于系统调试、性能分析以及安全监控等场景。本文将详细介绍如何通过三个关键步骤实现内核级的Inline Hook。 首先,理解...
本文将深入探讨`inline`函数的工作原理、使用场景及其潜在的陷阱,帮助开发者更好地理解和应用这一特性。 #### inline函数的基本概念 `inline`函数的目的是为了减少程序运行时的函数调用开销。在没有`inline`的...
`display: inline`、`display: block` 和 `display: inline-block` 是三种常见的值,它们各自具有不同的行为和用途。 1. **display: inline** - `display: inline` 使得元素以行内元素的方式呈现,这意味着它们会...
inline-java: 实现从Haskell调用任何JVM函数
Inline Hook是一种技术,主要用于在程序运行时修改函数的行为。它涉及到计算机编程中的底层技术,特别是逆向工程和软件调试领域。Inline Hook的核心是通过在原函数的代码中插入额外的指令来实现对函数调用的拦截,...
内联函数(inline)在C++编程语言中是一种优化手段,用于提高程序的运行效率。它的主要作用是在编译期间将函数体插入到每个调用该函数的地方,从而避免了函数调用时的开销,如函数调用的压栈、跳转以及返回等过程。...