CSDN VC编程经验总结.docx_第1页
CSDN VC编程经验总结.docx_第2页
CSDN VC编程经验总结.docx_第3页
CSDN VC编程经验总结.docx_第4页
CSDN VC编程经验总结.docx_第5页
已阅读5页,还剩551页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

-CSDN VC编程经验总结C+学习要点 1. 传指针时,我们可以通过指针来修改它在外部所指向的内容。但如果要修改外部指针所指向的对象是不可能的。例如传递外部指针到函数内来分配空间,必须传递指针的指针或指针的引用。 2. char carry10 = 0; 编译器会将其后所有的东西都置0; 3. 函数返回值为const时,返回的东西付给一个类型相同的标示后其不能为左值; 4. const int *i; int const *i; int * const i; 前两个功能相同,说明I所指向的内容不变;最后一个说明指针指向的地址不变,但内容可变。 5. 类中的const成员函数。定义为在原型后加const。常量函数不能修改类中的任何属性。但有两种方法可以修改。 a) (myclass *)this-member1 = values; b) 将一个成员定义成mutable即可被常量函数修改。 6. 类中的常量const 类型的,不能在类中被用来定义数组。而enum ONE=100; TWO=2;定义的ONE、TWO却可以。通常的enum定义的置分配问题:enum A L=9, Z;此时Z的值为10。 7. 用const定义的int可用来开辟数组,但const定义的常量数组中的元素,不能用来定义数组。 8. 用sizeof计算变量的空间,如果是数组,按实际空间返回;常量字符串(实际上是在静态内存区开辟的变量)sizeof返回比实际长度加一。如果是指针则不考虑它指向的空间大小,仅仅返回指针类型的大小。如果用sizeof计算函数的行参,即使是属组也仅仅返回一个相关类型指针的大小。 9. 形如int iarray = 12, 124, 433;编译器会自动给iarray分配3个元素的长度。元素长度的个数计算公式为sizeof(iarray) / sizeof(*iarray)。 10. 拷贝构造函数:当行参和实参结合时,如果是复杂对象的传值类型,则调用拷贝构造函数生成一个临时对象作为实参,退出函数时,临时对象被调用析构函数释放。当返回值是复杂对象是,也是调用拷贝构造函数来赋值。这就出现构造函数和析构函数被调用次数不相等的情况。拷贝构造函数的原型为A(A&),我们可在类中重载。(缺省的拷贝构造函数是使用位(bit)拷贝方法:浅层拷贝,不拷贝指针指向的内容)。 11. volatile类型的变量告诉编译器,本变量不需要进行代码优化。在多线程的应用中,我们如果读入一个变量到寄存器,此时时间片到期,去处理其他线程了,在重新获得处理机时,volatile类型告诉处理机,重新从变量读取数据到寄存器,而不是用寄存器数据直接处理,这样可以防止脏数据。 12. class 和struct在一定程度上有相同的功能,只不过前者缺省的成员是私有的,后者在缺省时成员为共有的。故而class不是c+必需的保留字 13. c和c+编译器,对相同的函数名编译后生成的相同的标示不同,故而在引用c的库文件时必须使用extern “C”告诉编译器,它是c的函数,按c的规则编译。通常我们使用的标准头文件已被处理过。 14. #include “filename”; #include ,前者先在当前目录下寻找文件,如果找不到再到系统规定的路径下找,后者直接到系统规定的路径下找。 15. 任何地方分配的静态变量(static),其生命周期和主进程相同。第二次定义一个已存在的static变量,对变量的内用无影响,但它的可见范围只在定义的范围内。(考研曾作错!)(从静态变量的特性不难理解,类中的static类型是所有对象共享的) 16. 内联函数(inline)在实现上实际和宏类似,在内联函数出现的地方将函数展开来避免函数调用时的出栈、如栈,提高效率。但内联函数的代价是:代码增大。inline函数适合成员函数和自由函数。在类中实现的函数自动为内联函数。inline必须定义到函数的实现上,例如:inline int PlusOne(int) 是无效的。友元函数在类的体内被实现自动变为内联函数。 17. #include #define DEBUG(X) cout#X=Xendl 其中的#X表示X被当作字符串输出。 18. assert(0 != 0); 如果assert中的条件为假,则运行期间回退出程序,且报告出错代码的行号。(#include ) 19. 静态对象在main结束或exit()被调用时才调用自身的析构函数。这意味着,在对象的析构函数中调用exit()是很危险的,有可能进入一个死循环中。调用abort()来退出函数,静态对象的析构函数并不会被调用。我们可以用atexit()来指定跳出main或调用exit时要执行的操作,用atexit注册的函数,可以在所有对象的析构函数之前调用。 void exit_fn2(void) printf(Exit function #2 calledn); /处理函数 atexit(exit_fn2); 20. 全局变量实际上用的是静态存储。静态变量的构造是在进入main之前调用的,在main结束时调用它的析构函数。变量的名字由小范围(c+而言): /*.cpp int a; /静态变量,但为 extern int a; 即它是全局的,外部可见的 static int b; /静态变量,static 和extern相反,只在*.cpp中有效,对其他单元(文件)是不可见的。函数的定义和上面相同。 main() 类的静态成员变量可以如下赋值:int X:s=23;(在*.cpp中,无论公私都可以) 21. 名字空间(namespace): 定义一个名字空间,然后使用unsing就可以将当前的类型上下文转换名字空间所定地的. namespace math enum signpositive, negative; class integer int i; sign s; public: interger(int I=0): i(i) sign Sign() . ;/end class interger A, B, C; interger divide(interger, interger); /no ; void q() using namespace math; interger A; /hides math:A A.Sign(negative); Math:A.Sign(positive); 22. 一般对于函数flaot f(int a, int b); 某些c+编译器编译后生成_f_int_int的名字,有些c编译器则生成_f的名字。故在c+中链接c的库函数时要用extern “C”告诉编译器,按c的规则来编译函数。类似的还有extern “C”#include “myhead.h”,c+还支持extern “C+”. 23. 在函数调用时,传引用也是将指针压栈。 24. 构造函数、析构函数、赋值构造函数、重载的=,四者的调用顺序:(三种函数都已实现) a) X x; X a=x; result: X:construct X:copy_struct b) X x; X a; a=x; Result: X:construct X:construct X:copy_stru operator = X:destruct 如果没有赋值构造函数则结果: X:construct X:construct operator = X:destruct (如果直接X a=x;这不掉用一般的构造函数,调用复制构造函数) 指向类的成员函数的指针:设 int X: a(void) X x; int (X: *pf)(void)= &X:a; (x.*pf)(); 指向成员变量的指针: 设int i; 是X的成员变量 int X:*pm = &X:i; X x; -CSDN VC编程经验总结 C+深度探索系列:智能指针(Smart Pointer) 一、剖析C+标准库智能指针(std:auto_ptr) 1.Do you Smart Pointer? 2.std:auto_ptr的设计原理 3.std:auto_ptr高级使用指南 4.你是否觉得std:auto_ptr还不够完美?二、C+条件,寻找构造更强大的智能指针(Smart Pointer)的 策略 1.支持引用记数的多种设计策略 2.支持处理多种资源 3.支持Subclassing 4.支持多线程条件下,线程安全的多种设计策略 5.其它多种特殊要求下,再构造三、Generic Programming基础技术和Smart Pointer 1.回首处理资源中的Traits技术 2.回首多线程支持的设计四、COM实现中,Smart Pointer设计原理五、著名C+库(标准和非标准)中的Smart Pointer现状-一、剖析C+标准库智能指针(std:auto_ptr) 1.Do you Smart Pointer? Smart Pointer,中文名:智能指针, 舶来品? 不可否认,资源泄露(resource leak)曾经是C+程序的一大噩梦.垃圾回收 机制(Garbage Collection)一时颇受注目.然而垃圾自动回收机制并不能 满足内存管理的即时性和可视性,往往使高傲的程序设计者感到不自在. 况且,C+实现没有引入这种机制.在探索中,C+程序员创造了锋利的 Smart Pointer.一定程度上,解决了资源泄露问题. 也许,经常的,你会写这样的代码: /x拟为class: / class x / public: / int m_Idata; / public: / x(int m_PARAMin):m_Idata(m_PARAMin) / void print() coutm_IdataDoSomething(); /#2 delete m_PTRx; 是的,这里可能没什么问题.可在复杂、N行、m_PTRclassobj所指对象生命周 期要求较长的情况下,你能保证你不会忘记delete m_PTRclassobj吗?生活中, 我们往往不应该有太多的口头保证,我们需要做些真正有用的东西.还有一个 更敏感的问题:异常.假如在#2方法执行期异常发生,函数执行终止,那么new 出的对象就会泄露.于是,你可能会说:那么就捕获异常来保证安全性好了. 你写这样的程式: void fook() A* m_PTRx = new A(m_PARAMin); try m_PTRx-DoSomething(); catch(.) delete m_PTRx; throw; delete m_PTRx; 哦!天哪!想象一下,你的系统,是否会象专为捕获异常而设计的. 一天,有人给你建议:用Smart Pointer,那很安全.你可以这样重写你的程序: void fook() auto_ptr m_SMPTRx(new x(m_PARAMin); m_SMPTRx-DoSomething(); OK!你不太相信.不用delete吗? 是的.不用整天提心吊胆的问自己:我全部delete了吗?,而且比你的delete 策略更安全. 然后,还有人告诉你,可以这样用呢: ok1. auto_ptr m_SMPTR1(new x(m_PARAMin); auto_ptr m_SMPTR2(m_SMPTR1); /#2 May be you can code #2 like this : auto_ptr m_SMPTR2; m_SMPTR2 = m_SMPTR1; ok2. auto_ptr m_SMPTR1(new int(32); ok3. auto_ptr m_SMPTR1; m_SMPTR1 = auto_ptr(new int(100); 也可以: auto_ptr m_SMPTR1(auto_ptr(new int(100); ok4. auto_ptr m_SMPTR1(new x(m_PARAMin); m_SMPTR1.reset(new x(m_PARAMin1); ok5. auto_ptr m_SMPTR1(new x(m_PARAMin); auto_ptr m_SMPTR2(m_SMPTR.release(); cout(*m_SMPTR2).m_Idataendl; ok6. auto_ptr fook() return auto(new int(100); ok7.and so on 但不可这样用: no1. char* chrarray = new char100; strcpy(chrarray,I am programming.); auto_ptr m_SMPTRchrptr(chrarray); /auto_ptr并不可帮你管理数组资源 no2. vectorauto_ptr m_VECsmptr; m_VECsmptr.push_back(auto_ptr(new int(100); /auto_ptr并不适合STL内容. no3. const auto_ptr m_SMPTR1(new x(100); auto_ptr m_SMPTR(new x(200); no4. x m_OBJx(300); auto_ptr m_SMPTR(&m_OBJx); no5 x* m_PTR = new x(100); auto_ptr m_SMPTR = m_pTR; no6.and so on 预先提及所有权的问题,以便下面带着疑问剖析代码? power1. auto_ptr m_SMPTR1(new x(100); auto_ptr m_SMPTR2 = m_SMPTR1; m_SMPTR2-print(); /输出:100. m_SMPTR1-print(); /! 非法的. power2. auto_ptr m_SMPTR(new x(100); auto_ptr returnfun(auto_ptr m_SMPTRin) return m_SMPTRin; auto_ptr = returnfun(m_SMPTR); /#5 /在上面的#5中,我要告诉你对象所有权转移了两次. /什么叫对象所有权呢? 2. std:auto_ptr的设计原理 上面的一片正确用法,它们在干些什么? 一片非法,它们犯了什么罪? 一片什么所有权转移,它的内部机智是什么? 哦!一头雾水?下面我们就来剖析其实现机制. 基础知识: a.智能指针的关键技术:在于构造栈上对象的生命期控制 堆上构造的对象的生命期.因为在智能指针的内部,存储 着堆对象的指针,而且在构析函数中调用delete行为. 大致机构如下: x* m_PTRx = new x(100);/#1 template auto_ptr private: T* m_PTR;/维护指向堆对象的指针,在auto_ptr定位后 . /它应该指向#1构造的对象,即拥有所有权. auto() delete m_PTR; . b.所有权转移之说 上面曾有一非法的程式片段如下: auto_ptr m_SMPTR1(new x(100); auto_ptr m_SMPTR2 = m_SMPTR1; m_SMPTR2-print(); /输出:100. m_SMPTR1-print(); /! 非法的. 按常理来说,m_SMPTR-print();怎么是非法的呢? 那是因为本来,m_SMPTR1维护指向new x(100)的指针, 可是m_SMPTR2 = m_SMPTR1;auto_ptr内部机制使得m_SMPTR1将对象的地址 传给m_SMPTR2,而将自己的对象指针置为0. 那么自然m_SMPTR-print();失败. 这里程序设计者要负明显的职责的. 那么auto_ptr为什么采取这样的策略:保证所有权的单一性. 亦保证了系统安全性. 如果多个有全权的auto_ptr维护一个对象,那么在你消除一个 auto_ptr时,将导致多个auto_ptr的潜在危险./-智能指针 2:下面我们以SGI-STL的auto_ptr设计为样本(去掉了无关分析的宏),来剖析其原理. #1 template class auto_ptr #2 private: #3 _Tp* _M_ptr; /定义将维护堆对象的指针 #4 public: #5 typedef _Tp element_type; /相关类型定义 #6 explicit auto_ptr(_Tp* _p = 0) _STL_NOTHROW : _M_ptr(_p) #7 auto_ptr(auto_ptr& _a) _STL_NOTHROW : _M_ptr(_a.release() #8 template auto_ptr(auto_ptr& _a) _STL_NOTHROW : _M_ptr(_a.release() /#6、#7、#8是auto_ptr构造函数的三个版本. /#6注释:传入对象的指针,构造auto_ptr.explicit关键字:禁止隐式转换. / 这就是ok2正确,而no5(隐式转换)错误的原因. /#7注释:拷贝构造函数. / 传入auto_ptr实例,构造auto_ptr. ok1、ok3使用了这个构造式. / 它是一个很关键的构造函数,在具体情况下,我们再分析 /#8注释:auto_ptr的模板成员,可在继承对象重载的基础上,实现特殊功能. / / 举例: / class A public: / virtual void fook()coutI am programmingendl; / /*.*/ ; / class B : public A / virtual void fook() coutI am workingendl; / /*.*/ ; / auto_ptr m_SMPTRa(new A(33);/实质: / auto_ptr m_SMPTRb(m_SMPTRa); /基类的指针可以赋给派生类的指针 / / auto_ptr m_SMPTRb(new B(44);/实质: / auto_ptr m_SMPTRa(m_SMPTRb); /派生类的指针不可赋给基类的指针 / / auto_ptr m_SMPTRa(new B(33); / ok! / m_SMPTRa-fook()将调用派生类B的fook() / m_SMPTRa-A:fook()将调用基类A的fook() / / auto_ptr m_SMPTRb(new A(33); / wrong! / / #9 auto_ptr& operator=(auto_ptr& _a) _STL_NOTHROW #10 if (&_a != this) delete _M_ptr; _M_ptr = _a.release(); #11 return *this; #12 #13 template #14 auto_ptr& operator=(auto_ptr& _a) _STL_NOTHROW #15 if (_a.get() != this-get() delete _M_ptr; _M_ptr = _a.release(); #16 return *this; #16 / / #9#16 两个版本的指派函数. / delete _M_ptr; 在指派前,销毁原维护的对象. / _a.release() ; release操作,详细代码参见#20#23. / 用于*this获得被指派对象, / 且将原维护auto_ptr置空. / no3使用了第一种指派. / 而权限转移正是_a.release()的结果. #17 auto_ptr() _STL_NOTHROW delete _M_ptr; /构析函数.消除对象.注意这里对对象的要求! #17 _Tp& operator*() const _STL_NOTHROW return *_M_ptr; #18 _Tp* operator-() const _STL_NOTHROW return _M_ptr; #19 _Tp* get() const _STL_NOTHROW return _M_ptr; / / 操作符重载. / #17注释:提领操作(dereference),获得对象. 见ok5用法. / #18注释:成员运算符重载,返回对象指针. / #19注释:普通成员函数.作用同于重载-运算符 / #20 _Tp* release() _STL_NOTHROW #21 _Tp* _tmp = _M_ptr; #22 _M_ptr = 0; #23 return _tmp; /上面已经详解 #24 void reset(_Tp* _p = 0) _STL_NOTHROW #25 delete _M_ptr; #26 _M_ptr = _p; / /传入对象指针,改变auto_ptr维护的对象 / 且迫使auto_ptr消除原来维护的对象 / 见ok3用法. / According to the C+ standard, these conversions are required. Most / present-day compilers, however, do not enforce that requirement-and, / in fact, most present-day compilers do not support the language / features that these conversions rely on. /下面这片段用于类型转化,目前没有任何编译器支持 /具体技术细节不诉. #ifdef _SGI_STL_USE_AUTO_PTR_CONVERSIONS #27 private: #28 template #29 struct auto_ptr_ref _Tp1* _M_ptr; auto_ptr_ref(_Tp1* _p) : _M_ptr(_p) ; #30 public: #31 auto_ptr(auto_ptr_ref _ref) _STL_NOTHROW : _M_ptr(_ref._M_ptr) #32 template #33 operator auto_ptr_ref() _STL_NOTHROW #34 return auto_ptr_ref(this-release(); #35 template operator auto_ptr() _STL_NOTHROW #36 return auto_ptr(this-release(); #37 #endif /* _SGI_STL_USE_AUTO_PTR_CONVERSIONS */ #38 ; OK!就是这样了. 正如上面原理介绍处叙说, 你需要正视两大特性: 1.构造栈对象的生命期控制堆上构造的对象的生命期 2.通过release来保证auto_ptr对对象的独权. 在我们对源码分析的基础上,重点看看: no系列错误在何处? no1. 我们看到构析函数template auto_ptr() _STL_NOTHROW delete _M_ptr; 所以它不能维护数组, 维护数组需要操作:delete _M_ptr; no2. 先提部分vector和auto_ptr代码: a.提auto_ptr代码 auto_ptr(auto_ptr& _a) _STL_NOTHROW : _M_ptr(_a.release() b.提vector代码 Part1: void push_back(const _Tp& _x) if (_M_finish != _M_end_of_storage) construct(_M_finish, _x); +_M_finish; else _M_insert_aux(end(), _x); Part2: template inline void construct(_T1* _p, /+ / const _T2& _value) + /+ / new (_p) _T1(_value); + /+ Part3. template void vector:_M_insert_aux (iterator _position, /+ / const _Tp& _x) + /+ if (_M_finish != _M_end_of_storage) construct(_M_finish, *(_M_finish - 1); +_M_finish; /+ / _Tp _x_copy = _x; + /+ copy_backward(_position, _M_finish - 2, _M_finish - 1); *_position = _x_copy; else const size_type _old_size = size(); const size_type _len = _old_size != 0 ? 2 * _old_size : 1; iterator _new_start = _M_allocate(_len); iterator _new_finish = _new_start; _STL_TRY _new_finish = uninitialized_copy (_M_start, _position, _new_start); construct(_new_finish, _x); +_new_finish; _new_finish = uninitialized_copy (_position, _M_finish, _new_finish); _STL_UNWIND(destroy(_new_start,_new_finish), _M_deallocate(_new_start,_len); destroy(begin(), end(); _M_deallocate(_M_start, _M_end_of_storage - _M_start); _M_start = _new_start; _M_finish = _new_finish; _M_end_of_storage = _new_start + _len; /-智能指针 3:从提取的vector代码,Part1可看出,push_back的操作行为. 兵分两路,可是再向下看,你会发现,无一例外,都 通过const _Tp& 进行拷贝行为,那么从auto_ptr提出的片段就 派上用场了. 可你知道的,auto_ptr总是坚持对对象的独权.那必须修改 原来维护的对象,而vector行为要求const _Tp&,这样自然会产生 问题.一般编译器是可以发觉这种错误的. 其实,STL所有的容器类都采用const _Tp&策略. /+ + 看了sutter和Josuttis的两篇文章中,都提及: + + STL容器不支持auto_ptr原因在于copy的对象只是获得所有权的对象, + + 这种对象不符合STL的要求.可是本人总感觉即时不是真正的复制对象,+ + 但我用vectorauto_ptr 的目的就在于维护对象,并不在乎 + + 所谓的完全对象.而且我用自己写的Smart Pointer配合STL容器工作, + + 很正常.那需要注意的仅仅是const问题. + + + /+ no3. 这个也是auto_ptr隐含的所有权问题引起的. const auto_ptr不允许修改. 随便提及:const对象不代表对象一点不可以改变. 在两种const语义下,都有方法修改对象或对象内

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论