??xml version="1.0" encoding="utf-8" standalone="yes"?> C++中的const关键字和#define有些怼Q?/span>#define只是用来做文本替换的Q会出现一些错误ƈ且不Ҏ查到。在C++代码中尽量?/span>const而不?/span>#define?/span> const的作用: 1?nbsp;const用于定义帔RQ?/span>const定义的常量编译器可以对其q行数据静态类型安全检查?/span> 2?nbsp;const修饰形参Q当参数是用戯定义cd或者抽象数据类型时Q用const引用传递而不是g递可以提高效率?/span> Void fun1(A a); Void fun2(A const &a); W二个函C需要生时对象,省去了对象构造析构消耗的旉 3?nbsp;const修饰函数q回|如果函数q回一?/span>const指针Q则函数q回值只能被const同类型指针接Ӟ否则error?/span> 4?nbsp;const修饰成员函数Q当你的成员函数不需要改变数据成员的值时Q就加上const修饰?/span> 本以Z函数main是首先被调用的函敎ͼ后来发现操作pȝ会调用一个启动函敎ͼ?/span>C++q行库进行初始化?/span> 本以Z函数main被返回之后操作系l将回收资源Q却不知一个重要的函数—atexit()?/span> E序退出的时候需要一些诸如释放资源的操作Q但是程序的退出有很多U,可能?/span>main函数l束范围一个g递给exit()Q也可能是一些其他的原因Q所以需要一U与E序l束方式无关的方法来q行E序退出时必要的处理?/span> 函数原型Q?/span>int atexit(void(*)(void)); 函数作用Q注册一个函敎ͼq个函数在程序结束的时候被调用 从结果中可以发现fun1和fun2两个函数在主函数l束之后被调用,而且调用的顺序与注册的顺序相反?/p>
CCDirector::sharedDirector()->getScheduler()Q?gt;setTimeScale(multi);
如果需要提升一倍的速度Q可以把multi设ؓ2.0f?br />
通过q样一个机制可以实现游戏内战斗倍数加速的功能?img src ="http://www.shnenglu.com/cxiaojia/aggbug/202374.html" width = "1" height = "1" />
]]>
Z避免同一个文件被include多次QC/C++中有两种方式Q一U是#ifndef方式Q一U是#pragma once方式。在能够支持q两U方式的~译器上Q二者ƈ没有太大的区别,但是两者仍然还是有一些细微的区别?/span>
方式一Q?/span>
#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__
... ... // 一些声明语?br style="margin: 0px; padding: 0px;" /> #endif
方式二:
#pragma once
... ... // 一些声明语?/span>
#ifndef的方式依赖于宏名字不能冲H,q不光可以保证同一个文件不会被包含多次Q也能保证内容完全相同的两个文g不会被不心同时包含。当Ӟ~点是如果不同头文件的宏名不小?#8220;撞R”Q可能就会导致头文g明明存在Q编译器却硬说找不到声明的状?#8212;—q种情况有时非常让h抓狂?/span>
#pragma once则由~译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文?#8221;是指物理上的一个文Ӟ而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名撞引发的奇怪问题。对应的~点是如果某个头文件有多䆾拯Q本Ҏ不能保证他们不被重复包含。当Ӟ相比宏名撞引发?#8220;找不到声?#8221;的问题,重复包含更容易被发现q修正?/span>
#pragma once方式产生?ifndef之后Q因此很多h可能甚至没有听说q。目前看?ifndef更受到推崇。因?ifndef受语a天生的支持,不受~译器的M限制Q?pragma once方式却不受一些较老版本的~译器支持,换言之,它的兼容性不够好。也许,再过几年{旧的编译器ȝ了,q就不是什么问题了?/span>
我还看到一U用法是把两者放在一LQ?/span>
#pragma once
#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__
... ... // 一些声明语?br style="margin: 0px; padding: 0px;" /> #endif
看v来似乎是惛_有两者的优点。不q只要用了#ifndef׃有宏名冲H的危险Q所以用两U方法似乎不能带来更多的好处Q倒是会让一些不熟悉的h感到困惑?/span>
选择哪种方式Q应该在了解两种方式的情况下Q视具体情况而定。事实上Q只要有一个合理的U定来避开~点Q我认ؓ哪种方式都是可以接受的。而这个已l不是标准或者编译器的责MQ应当由E序员来搞定?/span>
btwQ我看到GNU的一些讨Z乎是打算在GCC 3.4Q及其以后?Q的版本取消?pragma once的支持。不q我手上GCC 3.4.2和GCC 4.1.1仍然支持#pragma onceQ甚x有deprecation warning。VC6及其以后版本亦提供对#pragma once方式的支持。看来这一Ҏ已l稳定下来了?nbsp;
]]>
#include<sstream>
#include<string>
using namespace std;
template<class out_type,class in_value>
out_type convert(const in_value & t)
{
stringstream stream;
stream<<t;//向流中传?/span>
out_type result;//q里存储转换l果
stream>>result;//向result中写入?/span>
return result;
}
int main()
{
string s;
while(cin>>s)
{
double valdou=convert<double>(s);
int valint=convert<int>(s);
cout<<valdou<<endl;
cout<<valint<<endl;
}
return 0;
}
]]>
//功能Q内存复?br />//函数说明Q将memFrom指向的空间内容复制给memTo指向的空间内容,大小为size
void* mymemcpy(void* memTo,const void* memFrom,size_t size)
{
assert(memTo!=NULL);//判断是否为空
assert(memFrom!=NULL);//判断是否为空
char *tempFrom=(char*)memFrom;
char *tempTo=(char*)memTo;
while(size--)
*tempTo++=*tempFrom++; //复制
return memTo;
}
]]>
#include<iostream>
using namespace std;
class A//A是空c,~译器会用一个charcd标记q个c,大小?
{
};
class B:public A//Bl承了AQ但同样也是I类Q大ؓ1
{
};
class C:virtual public A//虚拟l承的时候编译器会安插一个指向父cȝ指针Q大ؓ4
{
};
class D//大小?
{
public:
int a;
static int b;//静态变量被攑֜静态存储区
};
class E //print函数不占内存I间Q大ؓ4
{
public:
void print(){cout<<"E"<<endl;}
private:
int a;
};
class F//虚函C占用一个指针大的内存Q系l需要用q个指针l护虚函数表。大ؓ8
{
public:
virtual void print(){cout<<"F"<<endl;}
private:
int a;
};
class G:public F//多了一个虚函数内存大小不变Q可见一个类只有一个虚函数指针。大ؓ8
{
public:
virtual void print(){cout<<"G"<<endl;}
virtual void print2(){cout<<"G2"<<endl;}
};
int main()
{
A a;
B b;
C c;
D d;
E e;
F f;
G g;
cout<<sizeof(A)<<" "<<sizeof(a)<<endl;//1 1
cout<<sizeof(B)<<" "<<sizeof(b)<<endl;//1 1
cout<<sizeof(C)<<" "<<sizeof(c)<<endl;//4 4
cout<<sizeof(D)<<" "<<sizeof(d)<<endl;//4 4
cout<<sizeof(E)<<" "<<sizeof(e)<<endl;//4 4
cout<<sizeof(F)<<" "<<sizeof(f)<<endl;// 8 8
cout<<sizeof(G)<<" "<<sizeof(g)<<endl;//8 8
return 0;
}
]]>
]]>
#include<iostream>
using namespace std;
void fun1()
{
cout<<"fun1"<<endl;
}
void fun2()
{
cout<<"fun2"<<endl;
}
int main()
{
atexit(fun1);//注册fun1Q主函数l止时调?/span>
atexit(fun2);//注册fun2Q主函数l止时调?/span>
cout<<"mian exit"<<endl;
return 0;
}
//q行l果Q?/span>
main exit
fun2
fun1
extern关键字的作用
1?nbsp;声明外部变量或者函?/span>
当你所需要的变量或者函数在另一个文仉边的时候,除了?/span>include包含Q还可以?/span>extern声明外部变量或者函数?br />
q里要注意的一ҎQextern关键字的作用仅仅是声明,没有分配内存I间Q声明的格式和定义的格式一定要严格相符?/p>
2?extern ”C” 链接指定为C函数?/p>
参数重蝲是C++的新Ҏ,在C中是没有的。在使用C++写代码的时候,如果调用C函数出错Q出错的原因见C++重蝲的实现机ӞQ则需要声明extern “C”链接指定ؓC函数库?/p>
静态全局变量与普通全局变量Q两者的存储方式相同Q都存储在静态区Q静态全局变量的作用域是定义该变量的源文gQ普通全局变量的作用域则是多个源文件的源程序,静态全局变量只初始化一ơ。?/span>
静态局部变量与普通局部变?/span>Q两者的作用域相同,存储方式不同Q静态局部变量存储在静态区Q普通局部变量存储在栈区。生存期也不同,静态局部变量的生存期ؓ整个E序Q普通局部变量的生存期仅为定义的那段I间。静态局部变量只初始化一ơ?/span>
静态函C普通函?/span>Q作用域不同Q静态函数的作用域仅在被定义的源文gQ普通函数在头文件的辅助下可以被外部讉K。静态函数在内存中只有一份,而普通函数在内存中可以有一份或者多份拷贝?/span>
C++l承?/span>C的全部特性,?/span>C实现了全面兼宏V?/span>C++又实C一些新的特性,比如说函数的重蝲?/span>
要实现函数的重蝲p改变原有的在C中函数定义的机制Q在C中定义函?/span>fun(int a,int b)Q编译器会把_fun写入W号库中Q?/span>fun()时会在符号库中找?/span>_funQƈ调用?/span>
?/span>C++中,׃要实现重载,需要加上参数的Ҏ,于是变成了_fun_int_intQ当函数?/span>fun(int a,double b)Ӟ~译器就会把_fun_int_double写入W号库,q样实C参数的多态?/span>
关于C++内存的划分,|上的ȝ已经很详l了。下Ҏ我{载的一部分?br />
一、一个经q编译的C/C++的程序占用的内存分成以下几个部分Q?/p>
1、栈区(stackQ:q译器自动分配和释放,存放函数的参数倹{局部变量的值等Q甚臛_数的调用q程都是用栈来完成。其操作方式cM于数据结构中的栈?/p>
2、堆区(heapQ?Q一般由E序员手动申请以及释放, 若程序员不释放,E序l束时可能由OS回收。注意它与数据结构中的堆是两回事Q分配方式类g链表?/p>
3、全局区(静态区Q(staticQ:全局变量和静态变量的存储是放在一块的Q初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在盔R的另一块区域。程序结束后ql释攄间?/p>
4、文字常量区Q常量字W串是攑֜q里的?E序l束后由pȝ释放I间?/p>
5、程序代码区Q存攑ևC的二q制代码?/p>
下面的例子可以完全展CZ同的变量所占的内存区域Q?/p>
二、栈QstackQ和堆(heapQ具体的区别?/p>
1、在甌方式?/p>
栈(stackQ? 现在很多人都UC为堆栈,q个时候实际上q是指的栈。它q译器自动理Q无需我们手工控制。例如,声明函数中的一个局部变?int b pȝ自动在栈中ؓb开辟空_在调用一个函数时Q系l自动的l函数的形参变量在栈中开辟空间?/p>
堆(heapQ? 甌和释攄E序员控Ӟq指明大。容易生memory leak?/p>
在C中用malloc函数?/p>
如:p1 = (char *)malloc(10);
在C++中用newq算W?/p>
如:p2 = new char[20];//(char *)malloc(10);
但是注意p1本n在全局区,而p2本n是在栈中的,只是它们指向的空间是在堆中?br />
new的本质还是用malloc的,但是new和mallocq是有很大区别:
Q?Qmalloc是C语言中的函数Qnew是C++中的操作W?br />
Q?Qmalloc的返回值是VOID*Qnewq回值是带有cd?br />
Q?Qmalloc只负责分配内存而不会调用类的构造函敎ͼnew不仅会分配内存,q会调用cȝ构造函?/p>
2、申请后pȝ的响应上
栈(stackQ?只要栈的剩余I间大于所甌I间Q系l将为程序提供内存,否则报异常提示栈溢出?/p>
堆(heapQ? 首先应该知道操作pȝ有一个记录空闲内存地址的链表,当系l收到程序的甌Ӟ会遍历该链表Q寻扄一个空间大于所甌I间的堆l点Q然后将该结点从I闲l点链表中删除,q将该结点的I间分配l程序。另外,对于大多数系l,会在q块内存I间中的首地址处记录本ơ分配的大小Q这P代码中的delete或free语句才能正确的释放本内存I间。另外,׃扑ֈ的堆l点的大不一定正好等于申L大小Q系l会自动的将多余的那部分重新攑օI闲链表中?/p>
3、申请大的限制
栈(stackQ?在Windows?栈是向低地址扩展的数据结构,是一块连l的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是pȝ预先规定好的Q在Windows下,栈的大小?MQ也有的说是1MQM是一个编译时q定的常数Q,如果甌的空间超q栈的剩余空间时Q将提示overflow。因此,能从栈获得的I间较小。例如,在VC6下面Q默认的栈空间大是1MQ好像是Q记不清楚了Q。当Ӟ我们可以修改Q打开工程Q依ơ操作菜单如下:Project->Setting->LinkQ在Category 中选中OutputQ然后在Reserve中设定堆栈的最大值和commit?/p>
注意Qreserve最gؓ4ByteQcommit是保留在虚拟内存的页文g里面Q它讄的较大会使栈开辟较大的|可能增加内存的开销和启动时间?/p>
堆(heapQ? 堆是向高地址扩展的数据结构,是不q箋的内存区域(I闲部分用链表串联v来)。正是由于系l是用链表来存储I闲内存Q自然是不连l的Q而链表的遍历方向是由低地址向高地址。一般来讲在32位系l下Q堆内存可以辑ֈ4G的空_从这个角度来看堆内存几乎是没有什么限制的。由此可见,堆获得的I间比较灉|Q也比较大?/p>
4、分配空间的效率?/p>
栈(stackQ?栈是机器pȝ提供的数据结构,计算Z在底层对栈提供支持:分配专门的寄存器存放栈的地址Q压栈出栈都有专门的指o执行Q这决定了栈的效率比较高。但E序员无法对其进行控制?/p>
堆(heapQ?是C/C++函数库提供的Q由new或malloc分配的内存,一般速度比较慢,而且Ҏ产生内存片。它的机制是很复杂的Q例如ؓ了分配一块内存,库函C按照一定的法Q具体的法可以参考数据结?操作pȝQ在堆内存中搜烦可用的够大的I间Q如果没有够大的I间Q可能是׃内存片太多Q,有可能调用pȝ功能d加程序数据段的内存空_q样有Z分到_大小的内存,然后q行q回。这样可能引发用h和核心态的切换Q内存的甌Q代价变得更加昂c显Ӟ堆的效率比栈要低得多?/p>
5、堆和栈中的存储内容
栈(stackQ?在函数调用时Q第一个进栈的是主函数中子函数调用后的下一条指令(子函数调用语句的下一条可执行语句Q的地址Q然后是子函数的各个形参。在大多数的C~译器中Q参数是由右往左入栈的Q然后是子函C的局部变量。注意:静态变量是不入栈的。当本次函数调用l束后,局部变量先出栈Q然后是参数Q最后栈指针指向最开始存的地址Q也是dC子函数调用完成的下一条指令,E序p点l运行?/p>
堆(heapQ?一般是在堆的头部用一个字节存攑֠的大,堆中的具体内ҎE序员安排?/p>
6、存取效率的比较
q个应该是显而易见的。拿栈上的数l和堆上的数l来_
上面代码中,arr1Q局部变量)是在栈中Q但是指向的I间在堆上Q两者的存取效率Q当然是arr高。因为arr[1]可以直接讉KQ但是访问arr1[1]Q首先要讉K数组的v始地址arr1Q然后才能访问到arr1[1]?/p>
总而言之,a而MQ?/p>
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜Q声明变量)、付钱、和吃(使用Q,吃饱了就赎ͼ不必理会切菜、洗菜等准备工作和洗、刷锅等扫尾工作Q他的好处是快捷Q但是自由度?/p>
使用堆就象是自己动手做喜Ƣ吃的菜_比较ȝQ但是比较符合自q口味Q而且自由度大?/p>
“C++11像一门新的语a?#8221; – Bjarne Stroustrup
C++11标准推出了很多有用的新特性。本文特别关注相比C++98更像是一门新语言的那部分Ҏ,因ؓQ?/p>
q些Ҏ改变了~写C++E序使用的代码风格和习语[TODO]Q通常也包括你设计C++函数库的方式。例如,你会看到更多参数和返回值类型ؓ指针(smart pointer)Q同时也会看到函数通过g递返回大型对?/p>
你将会发现在大多数的代码CZ中充斥着新特性的w媄。例如,几乎?行现代C++代码CZ都会使用?strong>auto
C++11的其他特性也很棒。但是请先熟悉下面这些,正是因ؓq些Ҏ的q泛使用使得C++11代码如同其他CL语言一hz、安全和高效Q与此同时保持了C++传统的性能优势?/p>
提示Q?/p>
auto
nullptr
始终使用nullptr表示一个null指针|l不要用数?或者NULL宏,因ؓ它们也可以代表一个整数或者指针从而生歧义?/p>
Range for
Z范围的@环得按序讉K其中的每个元素变得非常方ѝ?/p>
需要注意,使用autoq不改变代码的含义。代码仍然是静态类型E译注Q,每个表达式的cd都是清晰和明的QC++11只是不需要我们重复声明类型的名字。一些h刚开始可能会x在q里使用autoQ因为感觉好像没有(重复Q声明我们需要的cd意味着会碰巧得C个不同的cd。如果你惌明确地进行一?em>强制cd转换Q没有问题,声明目标cd好了。然而大多数情况下,只要使用auto可以了Q几乎不会出现错误地拿到一个不同类型的情况Q即便出现错误,C++的强静态类型系l也会由~译器让你知道这个错误,因ؓ你正试图讉K一个变量没有的成员函数或是错误地调用了该函数?/p>
译注Q动态类型语aQdynamic typing languageQ是指类型检查发生在q行期间Qrun-timeQ的语言。静态类型语aQstatic typing languageQ是cd查发生在~译期间Qcompile-timeQ的语言?/p>
指针Q无delete
请始l用标准智能指针以及非占有原始指针(non-owning raw pointer)。绝不要使用占有原生指针(owning raw pointer)和delete操作Q除非在实现你自q底层数据l构q种见的情况下Q即使在此时也需要在 class 范围内保持完好的装Q。如果只能够知道你是另一个对象唯一的所有者,请用unique_ptr来表C唯一所有权QTODO)。一?#8221;new T”表达式会马上初始化另一个引用它的对象,通常是一个unique_ptr?br />
nullptr
始终使用nullptr表示一个null指针|l不要用数?或者NULL宏,因ؓ它们也可以代表一个整数或者指针从而生歧义?/p>
Range for
Z范围的@环得按序讉K其中的每个元素变得非常方ѝ?br />
非成员(nonmemberQ?begin ?end
始终使用非成员begin和endQ因为它是可扩展的ƈ且可以应用在所有的容器cd(container type)Q不仅仅是遵循了STL风格提供?.begin ()?.end ()成员函数的容器,甚至数组都可以用?/p>
如果你用了一个非STL风格的collectioncdQ虽然提供了q代但没有提供STL?.begin ()?.end ()Q通常可以个类型编写自q非成员begin和end来进行重载。这样你可以用STL容器的编E风格来遍历该类型。C++11标准提供了示?C数组是q样一个类型,标准同时为数l提供了begin和end?/p>
Lambda 函数和算?/strong>
Lambda[TODO]是决定乾坤的因素Q它会你编写的代码变得更优雅、更快速。Lambda使得STL法的可用性提高了q?00倍。新q开发的C++函数库都是基于lambda可以用的前提Q例如,PPLQƈ且有些函数库甚至要求你编写lambda来调用函数库Q例如,C++ AMPQ?/p>
下面是一个快速示例:扑ֈv里面大于xq且于y的第一个元素。在C++11中,最单和q净的代码就是调用一个标准函数?br />
Move / &&
Move被认为是copy的最佳优化,管它也使得其他事情成ؓ可能比如信息被{发?/p>
Move语法改变了我们设计API的方式。我们可以更多地设计通过g递。ؓ你的cd启用move语法Q用时会比copy更有效?/p>
更多变化
q有更多CC++的特性。ƈ且我计划在未来编写更多深入C++11新特性以及其他特性的短文Q我们会知道更多q且喜欢上它?/p>
但目前,q是必须知道的新Ҏ。这些特性组成了CC++风格的核心,使得C++代码看v来和执行时像他们设计的那P你将会看到这些特性会出现在几乎每一D你看到或者编写的CC++代码中。ƈ且它们得现代C++更加q净、安全且快速,使得C++在未来的若干q仍然是我们产业的依靠?/p>
主要变更
2011-10-30:为Lambda增加C#lockCZ。重新组l智能指针首先介lunique_prt?/p>
文章Q?a target="_blank" style="color: #015fb6; text-decoration: none; ">伯乐在线