c++ 学习笔记

来源:互联网 发布:java可变参数不传入 编辑:程序博客网 时间:2024/06/04 17:42

c++学习笔记

    • c学习笔记
      • 线程管理
          • 线程锁
          • errprocmultiple definition of sqlca
          • static初始化要加锁
          • 多线程注意事项
      • 基础C
          • 数组指针
          • 指针地址与指针指向地址
          • 指针
          • 指针和引用的区别
          • UC 查看文件夹是否存在
      • 基础c
        • 语法
          • fstream的close
          • C 调用c库
          • 虚函数注意事项
          • STL string 查找字符串
          • 异常
          • 禁止拷贝构造和拷贝赋值
          • C 模板 undefined reference to
          • 虚函数与虚析构
        • 设计模式
          • 单例模式
      • c11
      • STL
          • 仿函数
      • 编译
          • ifndef
      • 其他
          • errwhich is of non-class type
          • undefined reference to sqlca
          • 使用安全函数
          • static
          • STL容器特征总结

线程管理

线程锁
#include <pthread.h>1.在外部定义并初始化,否则锁不稳定pthread_mutex_t wt_mtx;    pthread-mutex_init(&wt_mtx,NULL);在方法中引用    pthread_mutex_lock(&p_writelog->wt_mtx);    //此处写需枷锁的写法    pthread_mutex_unlock(&p_writelog->wt_mtx);2.锁的中间的代码若不确定正确性,或可能出现问题,要对其进行加锁,否则可能导致锁不能被打开,阻塞其他线程。当然,这是为了缩短开发时间的方式,否则应该追踪块内的错误,正常情况下不应将逻辑错误放过。lock();    try{}catch(...){    unlock();    }    unlock();3.就目前线程开发死锁问题如果已在所有出口上已解锁,而实际上其他线程最终无法获得该锁的原因基本上可以确认为锁块内的代码出现了非法的内存操作,研究代码,在不关注外部输入情况下,审视锁块内可能潜藏的问题。
err:proc:multiple definition of `sqlca’
这个问题一般是Linux g++编译器与proc兼容导致。在pc文件最开始地方(即第一个包含的头文件之前加上):#define SQLCA_STORAGE_CLASS extern
static初始化要加锁
/*这里需要注意的是,C++0X以后,要求编译器保证内部静态变量的线程安全性,可以不加锁。但C++ 0X以前,仍需要加锁。*/class SingletionInside{private:    SingletionInside(){}public:   static SingletonInside* getInstance()   {        Lock();//not needed after C++0x        static SingletonInside instance;        Unlock();// not needed after C++0x        return instance;   }};
多线程注意事项
1. 如想用一个类返回new出新类注意用指针进行传递,使用对象传递可能造成多次调用使用一个对象,发生对象粘连2. 禁用这种写法 client = &p_server->accept_client(); //该类返回客户端对象 正确方法:按指针传递3. 没个线程都能抛出异常,但尽量将异常在本线程中捕获并处理,然后信号到主线程。自定义异常不能跨线程捕获4. 单例模式入口程序不要太大,避免多线程代码经常经过static成员初始化语句,否则访问时可能异常。5. 线程内不要同时开销同一对象过为频繁,因为其他线程也会这么做导致资源冲突(有空研究),合理的方式是对这些资源定义一次,尽可能少的初始化和析构该对象。

基础C

数组指针
1. 直接取数组名得到的是数组起始指针,可直接用于memcpy等。2. 使用数据名[pot]要注意,该变量实际是一个char型而非指针,若用于memcpy要注意需再取址一次,否则引发段错误。3. 
指针地址与指针指向地址

++总结:*p 指针指向内容 ,p 指针指向地址, &p 指针所在地址++

 int *q;                                           //定义一个整型的指针变量q  q=&a;                                             //将变量a的地址放在指针变量qprintf("变量a的地址为: %p\n",&a);                          //输出a的地址  printf("变量a的值为: %d\n",a);                                //输出a的值  printf("指针变量q的地址为: %p\n",&q);                  //输出q的地址  printf("指针变量q的值为: %p\n",q);                         //输出q的地址的值  printf("指针变量q所指向的值为: %d\n",*q);            //输出a的地址 
指针
1. const 位置对指针影响   const Writelog* wr; //基本上没有意义,因为不能指向成员 //即指针的目标内容不能改变   Writelog* const wr; //固定对象地址,不能用于指向其他对象 //指针本身指向不能改变
指针和引用的区别
(1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。如:int a=1;int *p=&a;int a=1;int &b=a;上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单元的地址。而下面2句定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单元。(2)可以有const指针,但是没有const引用;(3)指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)(4)指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;(5)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。(6)"sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小;(7)指针和引用的自增(++)运算意义不一样;
UC 查看文件夹是否存在
#include <unistd.h>    int Ret = access(file_path.c_str(),0);    if (Ret != -1 ) cout <<"文件夹存在"<<endl;    Ret = access(file_path.c_str(),0);    if (Ret != -1) cout <<"文件夹有读写权限"<<endl;    else cout <<"文件夹没有读写权限"<<endl;

基础c++

语法

fstream的close

函数会自动析构函数,因此即便是new出的文件流,在执行close时对象也会被析构,因此不用再delete对象,否则double free。

C++ 调用c库
1. 首先在多个链接库生成主程时要注意包的顺序,一般来说被依赖越多的库存放位置约靠后,各个·a文件依次向后方整体依赖。2. c库注意仍用gcc -c进行编译,不要用g++3. 在cpp文件调用时注意使用extern "C"{    #include "XXX.h"//此处把c编译的包头文件放在这里,防止做换名处理    }
虚函数注意事项
1. 一个虚函数若有两个或两个以上的子类,必须定义其虚析构,否则会使构造出现未定义。
STL string 查找字符串
    string::size_type pot;    pot = file_name.find_last_of('/',-1);    string dir_path = file_name.substr(0,pot);
异常
H文件class BaseError{public:    virtual void hode_exp () const = 0;    string m_file;};class LogFileError : public BaseError{public:    void hode_exp () const;};CPP文件对父类hode_exp进行定义,异常OK异常抛出if(this->p_file->write_append(v_log) == -1){        throw LogFileError(__FILE__);    }异常捕获 try{        //可抛出异常模块    }    catch(BaseError& ex){//此处可直接按父类捕获       //处理逻辑       //注:如处理模块不向上抛出,或不主动停止程序,程序可继续进行       //若想程序停止可继续向上抛出    }
禁止拷贝构造和拷贝赋值
H文件private:    //禁用拷贝构造和拷贝赋值    TcpSrv(const TcpSrv& orig);    const TcpSrv& operator=(const TcpSrv& );CPP文件TcpSrv::TcpSrv(const TcpSrv& orig){}const TcpSrv& TcpSrv::operator=(const TcpSrv& ){}
C++ 模板 undefined reference to
解决方法一,在main.cpp中#include "queue.cpp",而非"queue.h",这种方式就如同将队列类的声明实现放在同一文件中。解决方法二,在queue.h中,代码部分结尾处#include "queue.cpp",并且去掉queue.cpp里的包含语句,这与上述方式如出一辄,只是在main.cpp中看上去就像习惯中的方案一样。
虚函数与虚析构
虚函数用于向下指定一个需要在基类中实现的函数。纯虚函数 virtual void Eat() = 0; 直接=0 不要 在cpp中定义就可以了。纯虚函数相当于接口,不能直接实例话,需要派生类来实现函数定义。虚函数子类不一定要实现,但纯虚函数子类必须实现。虚析构通常析构都使用虚析构,因为若在有继承情况下,没有虚析构,只会调用基类的析构函数,而子类额外出来的部分不会被析构,因此一般将子类析构函数写成析构函数。

设计模式

单例模式
class CSingleton  {  private:      CSingleton(){}  //构造函数是私有的      static CSingleton *m_pInstance;  //这个需跟在main文件初始化public:      static CSingleton * GetInstance(){          if(m_pInstance == NULL)  //判断是否第一次调用              m_pInstance = new CSingleton();          return m_pInstance;      }  };  

c++11

1. 编译 -std=c++0x2. 使用ucsendrecv注意 ::send,::recv,因为c++11库也加入了该部分函数

STL

仿函数
 仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了。  有些功能的的代码,会在不同的成员函数中用到,想复用这些代码。                            1)公共的函数,可以,这是一个解决方法,不过函数用到的一些变量,就可能成为公共的全局变量,再说为了复用这么一片代码,就要单立出一个函数,也不是很好维护。                            2)仿函数,写一个简单类,除了那些维护一个类的成员函数外,就只是实现一个operator(),在类实例化时,就将要用的,非参数的元素传入类中。#include <iostream>  #include <algorithm>  using namespace std;  template<typename T>  class display  {  public:      void operator()(const T &x)      {          cout<<x<<" ";       }   };   int main()  {      int ia[]={1,2,3,4,5};      for_each(ia,ia+5,display<int>());       return 0;   }   

编译

ifndef
条件编译 并拒绝已经获取的宏定义头文件重复引用会在.obj合成可执行程序时合并被重复引用的头文件条件编译(如操作系统,编译环境)则会在合成obj时过滤掉无用代码

其他

err:which is of non-class type
这种错误一般是因为较低级的错误引起的,本次,是在实例化对象时未使用指针方式初始化。改用new后正确
undefined reference to `sqlca’
这个问题应该也是由于链接库位置的原因,但目前未找到解决办法,是在main入口处加上<sqlca.h>
使用安全函数
不安全函数有潜在风险,通过格式%.*s控制,另一方面尽量使用安全函数,确保过程按思路执行。sprintf ->snprintfsvprintf->svnprintfstrcpy -> strncpy
static
静态局部变量的特点(括号内为note:2,也就是局部变量的对比):(1)该变量在全局数据区分配内存(局部变量在栈区分配内存);(2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化(局部变量每次函数调用都会被初始化);(3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0(局部变量不会被初始化);(4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,也就是不能在函数体外面使用它(局部变量在栈区,在函数结束后立即释放内存);静态全局变量:定义在函数体外,用于修饰全局变量,表示该变量只在本文件可见。静态数据成员:用于修饰 class 的数据成员,即所谓“静态成员”。这种数据成员的生存期大于 class 的对象(实体 instance)。静态数据成员是每个 class 有一份,普通数据成员是每个 instance 有一份,因此静态数据成员也叫做类变量,而普通数据成员也叫做实例变量。静态成员函数:用于修饰 class 的成员函数。
STL容器特征总结
2011-11-09 11:10:50|  分类: STL|举报|字号 订阅STL中顺序容器类和关联式容器类的主要特征如下:(1)Vector 1、内部数据结构:连续存储,例如数组。 2、随机访问每个元素,所需要的时间为常量。 3、在末尾增加或删除元素所需要时间与元素数目无关,在中间或开头增加或删除元素所需时间随元素数目呈线性变化。 4、可动态增加或减少元素,内存管理自动完成,但程序员可以使用reserve()成员函数来管理内存。 5vector的迭代器在内存重新分配时将失效(它所指向的元素在该操作的前后不再相同)。当把超过capacity()-size()个元素的插入vector中时,内存会重新分配,所有的迭代器都将失效;否则,指向当前元素以后的任何元素的迭代器都将失效。    建议:使用vector时,用reserve()成员函数预先分配需要的内存空间,它既可以保护迭代器使之不会失效,又可以提高运行效率。(2deque 1、内部数据结构:连续存储或分段连续存储,具体依赖于实现。 2,随机访问每个元素,所需要的时间为常量。 3、在开头和结尾增加元素所需时间与元素数目无关,在中间增加或删除元素所需时间随元素数目呈线性变化。 4、可动态增加或减少元素,内存管理自动完成,不提供用于内存管理的成员函数。 5、增加任何元素都将使deque的迭代器失效。在deque的中间删除元素将使迭代器失效。在deque的头或尾删除元素时,只有指向该元素的迭代器失效。(3list 1、内部数据结构:双向环状链表。 2、不能随机访问一个元素。 3、可双向遍历。 4、在开头、末尾和中间任何地方增加或删除元素所需时间都为常数。 5、可动态增加或减少元素,内存管理自动完成。 6、增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其他迭代器都不会失效。(4)slist  1、内部数据结构:单向链表。  2、不可双向遍历,只能从前向后遍历。  3、其他特性与list相同。     建议:尽量不要使用slist的insert,erase,previous等操作。因为这些操作需要向前遍历,但是slist不能直接向前遍历,所以它会从头开始向后搜索,所需时间与位于当前元素之前的元素个数成正比。slist专门提供了insert_after,earse_after等函数进行优化。但若经常需要向前遍历,建议选用list。(5stack适配器,它可以将任意类型的序列容器转换为一个堆栈,一般使用deque作为支持的序列容器。元素只能后进先出。不支持遍历操作。(6queue   适配器,它可以将任意类型的序列容器转换为一个队列,一般使用deque作为支持的序列容器。   元素只能先进先出。   不支持遍历操作。(7)priority_queue   适配器,它可以将任意类型的序列容器转换为一个优先队列,一般使用vector作为底层存储结构。   只能访问第一个元素,不支持遍历操作。   第一个元素始终是优先级最高的元素。   建议:当需要stackqueue或priority_queue这样的数据结构时,直接使用对应的容器类,不要使用deque去做它们类似的工作。(8set   1、键和值相等。   2、键唯一。   3、元素默认按升序排列。   4、如果迭代器指向的元素被删除,则该迭代器失效。其他任何增加、删除元素的操作都不会使该迭代器失效。(9multiset键可以不唯一。其他特点与set相同。(10)hash_set与set相比较,它里面的元素不一定是经过排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然跟hash函数有关)。其他特点与set相同。(11)hash_multiset 1、键可以不唯一。 2、其他特点与hash_set相同。(12map 1、键唯一。 2、元素默认按键的升序排列。 3、如果迭代器所指向的元素被删除,则该迭代器失效。其他任何增加、删除元素的操作都不会使迭代器失效。(13multimap 1、键可以不唯一。 2、塔器特点与map相同。(14)hash_map 1、与map相比较,它里面的元素不一定是按键值排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然也与hash函数有关)。 2、其他特点与map相同。(15)hash_multimap 1、键可以不唯一。 2、其他特点与hash_map相同。建议:     1>当元素的有序比搜索速度更重要时,应选用setmultisetmapmultimap。否则,选用hash_set,hash_multiset,hash_map或hash_multimap。     2>若经常需要在序列容器的开头或中间增加或删除元素时,应选用list3>当容器作为参数被传递时,请采用引用传递方式。否则将调用容器的拷贝构造函数,其开销是难以想象的