zoukankan      html  css  js  c++  java
  • C/C++(C++内存管理,内联函数,类型转换,命名空间,string类)

    ---恢复内容开始---

    ## 内存管理 ### new/delete C语言中提供了 malloc 和 free 两个系统函数,#include "stdlib.h"库函数,完成对堆内存的申请和释放。而 c++则提供了两关键字 new 和 delete ,new delete关键字。 **生成单变量空间和数组空间**
    int *p = (int *)malloc(sizeof(int));//c
    
    int *p = static_cast<int*>(malloc(sizeof(int)));//c过渡到c++
    int *p = new int(200);//C++单变量初始化
    cout<< *p<<endl;
    string *ps = new string("assassin");
    cout<< *ps<<endl;
    
    struct Stu
    {
       int age;
       string name;
    };
    Stu* pStu = new Stu{23,"assassin"};
    cout<< pStu->age<<endl;
    cout<< pStu->name<<endl;
    //23
    //assassin
    
    

    生成数组

    char *p = new int[4];
    strcpy(p,"china");
    cout<<p<<endl;
    
    int *pi = new int[5];
    //int *pi = new int[5]{0};//初始化0,一般不这样
    memset(pi,0,sizeof(int[5]));//初始化
    for(int i = 0;i < 5;i++)
    {
        cout<<pi[i]<<endl;
    }
    
    

    生成指针数组:

    char **p = new char*[5]{NULL};
    p[0] = "assassin";
    p[1] = "automan";
    p[2] = "wunworld";
    while(*p)
    {
        cout<<*p++<<endl;
    }
    /*
    assassin
    automan
    wunworld
    */
    

    生成二维数组;

    int (*pa)[4] = new int[3][4]{{0}};//初始化
    for(int i = 0;i < sizeof(int[3][4])/sizeof(int[4]);i++)
    {
        for(int j = 0;j < 4;j++)
        {
            cout<<pa[i][j]<<" ";
        }
        cout<<endl;
    }
    /*
    0 0 0 0
    0 0 0 0
    0 0 0 0
    */
    //多维
    int (*ppp) [3][4][5] = new int[2][3][4];
    

    释放delete:

    int *p = new int;
    delete p;
    int *a = new int[100];
    delete []a;//正确的释放
    delete a;//只把第一个释放了
    
    int (*aa)[4] = new int[3][4];
    delete []aa;//多位的数组也是一个方括号,底层用递归
    

    注意事项

    1,new/delete 是关键字,效率高于 malloc 和 free.
    2,配对使用,避免内存泄漏和多重释放。
    3,避免,交叉使用。比如 malloc 申请的空间去 delete,new 出的空间被 free;

    //c
    int *p = (int *)malloc(100);
    if(NULL == p)
        return -1;
    //c++
    int *pi = new (std::nothrow) int[100];
    if(pi == NULL)
        return -1;
    
    

    内联函数(inline function)

    c语言中有宏函数的概念。宏函数的特点是内嵌到调用代码中去,避免了函数调用的开销。但是由于宏函数的处理发生在预处理阶段,缺失了语法检测和有可能带来的语意差错,容易使得内存text段体积变大,不会类型检查。

    #define SQR(i) ((i)*(i))
    int main()
    {
        int i=0;
        while(i<5)
        {
            // printf("%d
    ",SQR(i++));
            printf("%d
    ",sqr(i++));
        }
        return 0;
    }
    
    int sqr(int i)
    {
        return i*i;
    }
    /*
    优点:一段高度抽象的逻辑,不易产生歧义,是的text段体积变小,会类型检查。
    缺点:函数调用的压栈与出栈的开销
    */
    

    内联函数兼有宏和函数的优点。系统自己有一套优化方案,inline变成了给编译器的一种建议。

    inline int sqr(int i)
    {
        return i*i;
    }
    

    评价
    优点:避免调用时的额外开销(入栈与出栈操作)
    代价:由于内联函数的函数体在代码段中会出现多个“副本”,因此会增加代码段的空间。
    本质:以牺牲代码段空间为代价,提高程序的运行时间的效率。
    适用场景:函数体很“小”,且被“频繁”调用。

    强制类型转化

    static_cast 
    //对于隐时类型可以转化的
    reinterpret_cast
    //对于无隐式的类型转化,static_cast不可用
    const_cast
    //
    dynamic_cast
    //
    

    static_cast

    float a = 5.6;
    int b = 5;
    
    b = static_cast<int>(a);//把a转成int赋值给b
    
    void *p,int *q;
    p = q;//可以
    q = p;//不可以,任何指针都可以赋值给void *类型,但是void *类型不可以赋值给指针类型。
    q = static_cast<int*>(p);
    
    

    reinterpret_cast

    int a[5] = {1,2,3,4,5};
    int *p = reinterpret_cast<int*>((reinterpret_cast<int>(a)+1));
    

    const_cast
    ( 脱) 常类型转换,只能引用与指针与引用
    const 一定不可以修改

    void func(const int &r)
    {
    
    }
    void func2(int & v)
    {
        cout<<v<<endl;
    }
    
    int main()
    {
        const int a = 19;
        func(10);//可以
        func(a+10);//可以,应为参数中有const修饰。
        func2(const_cast<int&>(a));//因为a是const int类型
        int & ra = const_cast<int&>(a);
        ra = 200;
        cout<<"a = "<<a<<" ra= "<<ra<<endl;
        cout<<"&a = "<<&a<<" ra = "<<&ra<<endl;
        /*
        a = 19 ra = 200
        &a = 0x... 不一样
        */
    }
    

    用来移除对象的常量性(cast away the constness)使用 const_cast 去除 const 限定的目的不是为了修改它的内容,使用 const_cast 去除 const 限定,通常是为了函数能够接受这个实际参数。
    可以改变 const 自定义类的成员变量,但是对于内置数据类型,却表现未定义行为 .

    const 常变量

    #defined N 200 //宏,在预处理的阶段发生了替换
    const int a = 100;//编译阶段发生了替换
    //const 永远不会发生改变
    

    命名空间(namespace scope)

    //全局就是无名空间
    int v = 55;
    int main()
    {
        int *p = &v;//访问全局的
        int v =5;
        cout<<v<<endl;//5
        cout<<*p<<endl;//55
    
        cout<<::v<<endl;//::作用域运算符,前面要命名空间,平常调配用的函数之前省略::
        
        return 0;
    }
    
    

    namespace 是对全局命名空间的再次划分

    #include<iostream>
    using namespace std;
    namespace Spac{
        int a;//全局变量 
        struct Stu{};//数据类型 
        void func();//函数 
        namespace//其它命名空间 
    }
    

    使用:

    #include<iostream>
    using namespace std;
    namespace Space {
        int x;
        int y;
    }
    namespace Other {
        int x;
        int y;
    }
    int main()
    {
        Space::x = 200;//这种与本地的不会冲突
        cout<<Space::x<<endl;//200
    
        using Space::x;//在这作用域内的x都是Space命名空间中的x
        x = 20;
        cout<<x<<endl;
    
        using Space Space;//直接把Space这个命名空间打开
        x = 20;
        y = 30;
    
    
        return 0;
    }
    

    各种之间冲突解决

    利用最小单位的作用域块

    #include<iostream>
    using namespace std;//标中库空间命名
    namespace Space {
        int x;
        int y;
    }
    namespace Other {
        int x;
        int y;
    }
    int main()
    {
        {
            using Space Space;
            x = 20;
            y = 30;
        }
        {
            using Space Other;
            x = 50;
            y = 70;
        }
        int x,y;
    
        return 0;
    }
    

    支持嵌套

    namespace Space {
        int x;
        int y;
        namespace Other {
            int m;
            int n;
        }
    }
    int main()
    {
        using namespace Space::Other;//使用Other命名空间中的变量,不建议嵌套
        m = 30;
        return 0;
    }
    

    协同开发中的使用

    namespace Space {
        int x;
    }
    namespace Space {
        int y;
    }//命名空间相同会自动合并
    int main()
    {
        using namespace Space;
        x = 10;
        y = 20;
        return 0;
    }
    
    

    系统string类

    string是一个类而非关键字,初始化比较灵活(类似js中var)

    string s = "assassin";//赋值
    string s2 = "assassin1";
    cout<<s2.size()<<endl;//大小
    string s3 = "wunworld";
    s3 += s2;//拼接
    if(s == s2)//比较 
        cout<<"s = s2"<<endl;
    else if(s > s2)
        cout<<"s > s2"<<endl;
    else
        cout<<"s < s2"<<endl;
    
    char buf[1024];
    strcpy(buf,s.c_str());
    //如果和字符连用时,一定用c_str(),返回的是char *类型
    //交换swap(string &s2)成员函数
    s.swap(s2);
    
    

    查找:

    int find(char c, int pos = 0);
    int find(char * s, int pos = 0);
    //返回下标值,没有找到返回-1,默认从 0 下标开找
    

    eg:

    string s = "assassin";
    int n = s.find("i",0);
    cout<<n<<endl;//6
    

    string 类型数组

    string sArray[10] = {
                            "0",
                            "1",
                            "22",
                            "333",
                            "4444",
                            "55555",
                            "666666",
                            "7777777",
                            "88888888",
                            "999999999",
    };
    for(int i=0; i<10; i++)
    {
        cout<<sArray[i]<<endl;
    }
    

    string 数组是高效的,如果用二维数组来存入字符串数组的话,则容易浪费空间,此时列数是由最长的字符串决定。如果用二级指针申请堆空间,依据大小申请相应的空间,虽然解决了内存浪费的问题,但是操作麻烦。用 string 数组存储,字符串数组的话,效率即高又灵活。

    学习C++的建议:
    1、在 C++中几乎不需要用宏,用 const 或 enum 定义显式的常量,用 inline 避免函数 调用的额外开销,用模板去刻画一族函数或类型,用 namespace 去避免命名冲突。
    2、不要在你需要变量之前去声明,以保证你能立即对它进行初始化。
    3、不要用 malloc,new 运算会做的更好。
    4、避免使用 void*、指针算术、联合和强制,大多数情况下,强制都是设计错误的指示器。
    5、尽量少用数组和 C 风格的字符串,标准库中的 string 和 vector 可以简化程序。
    6、更加重要的是,试着将程序考虑为一组由类和对象表示的相互作用的概念,而不是一堆数据结构和一些可以拨弄的二进制

    ---恢复内容结束---

    ## 内存管理

    new/delete

    C语言中提供了 malloc 和 free 两个系统函数,#include "stdlib.h"库函数,完成对堆内存的申请和释放。而 c++则提供了两关键字 new 和 delete ,new delete关键字。
    生成单变量空间和数组空间

    int *p = (int *)malloc(sizeof(int));//c
    
    int *p = static_cast<int*>(malloc(sizeof(int)));//c过渡到c++
    int *p = new int(200);//C++单变量初始化
    cout<< *p<<endl;
    string *ps = new string("assassin");
    cout<< *ps<<endl;
    
    struct Stu
    {
       int age;
       string name;
    };
    Stu* pStu = new Stu{23,"assassin"};
    cout<<pStu->age<<endl;
    cout<<pStu->name<<endl;
    //23
    //assassin
    

    生成数组

    char *p = new int[4];
    strcpy(p,"china");
    cout<<p<<endl;
    
    int *pi = new int[5];
    //int *pi = new int[5]{0};//初始化0,一般不这样
    memset(pi,0,sizeof(int[5]));//初始化
    for(int i = 0;i < 5;i++)
    {
        cout<<pi[i]<<endl;
    }
    
    

    生成指针数组:

    char **p = new char*[5]{NULL};
    p[0] = "assassin";
    p[1] = "automan";
    p[2] = "wunworld";
    while(*p)
    {
        cout<<*p++<<endl;
    }
    /*
    assassin
    automan
    wunworld
    */
    

    生成二维数组;

    int (*pa)[4] = new int[3][4]{{0}};//初始化
    for(int i = 0;i < sizeof(int[3][4])/sizeof(int[4]);i++)
    {
        for(int j = 0;j < 4;j++)
        {
            cout<<pa[i][j]<<" ";
        }
        cout<<endl;
    }
    /*
    0 0 0 0
    0 0 0 0
    0 0 0 0
    */
    //多维
    int (*ppp) [3][4][5] = new int[2][3][4];
    

    释放delete:

    int *p = new int;
    delete p;
    int *a = new int[100];
    delete []a;//正确的释放
    delete a;//只把第一个释放了
    
    int (*aa)[4] = new int[3][4];
    delete []aa;//多位的数组也是一个方括号,底层用递归
    

    注意事项

    1,new/delete 是关键字,效率高于 malloc 和 free.
    2,配对使用,避免内存泄漏和多重释放。
    3,避免,交叉使用。比如 malloc 申请的空间去 delete,new 出的空间被 free;

    //c
    int *p = (int *)malloc(100);
    if(NULL == p)
        return -1;
    //c++
    int *pi = new (std::nothrow) int[100];
    if(pi == NULL)
        return -1;
    
    

    内联函数(inline function)

    c语言中有宏函数的概念。宏函数的特点是内嵌到调用代码中去,避免了函数调用的开销。但是由于宏函数的处理发生在预处理阶段,缺失了语法检测和有可能带来的语意差错,容易使得内存text段体积变大,不会类型检查。

    #define SQR(i) ((i)*(i))
    int main()
    {
        int i=0;
        while(i<5)
        {
            // printf("%d
    ",SQR(i++));
            printf("%d
    ",sqr(i++));
        }
        return 0;
    }
    
    int sqr(int i)
    {
        return i*i;
    }
    /*
    优点:一段高度抽象的逻辑,不易产生歧义,是的text段体积变小,会类型检查。
    缺点:函数调用的压栈与出栈的开销
    */
    

    内联函数兼有宏和函数的优点。系统自己有一套优化方案,inline变成了给编译器的一种建议。

    inline int sqr(int i)
    {
        return i*i;
    }
    

    评价
    优点:避免调用时的额外开销(入栈与出栈操作)
    代价:由于内联函数的函数体在代码段中会出现多个“副本”,因此会增加代码段的空间。
    本质:以牺牲代码段空间为代价,提高程序的运行时间的效率。
    适用场景:函数体很“小”,且被“频繁”调用。

    强制类型转化

    static_cast 
    //对于隐时类型可以转化的
    reinterpret_cast
    //对于无隐式的类型转化,static_cast不可用
    const_cast
    //
    dynamic_cast
    //
    

    static_cast

    float a = 5.6;
    int b = 5;
    
    b = static_cast<int>(a);//把a转成int赋值给b
    
    void *p,int *q;
    p = q;//可以
    q = p;//不可以,任何指针都可以赋值给void *类型,但是void *类型不可以赋值给指针类型。
    q = static_cast<int*>(p);
    
    

    reinterpret_cast

    int a[5] = {1,2,3,4,5};
    int *p = reinterpret_cast<int*>((reinterpret_cast<int>(a)+1));
    

    const_cast
    ( 脱) 常类型转换,只能引用与指针与引用
    const 一定不可以修改

    void func(const int &r)
    {
    
    }
    void func2(int & v)
    {
        cout<<v<<endl;
    }
    
    int main()
    {
        const int a = 19;
        func(10);//可以
        func(a+10);//可以,应为参数中有const修饰。
        func2(const_cast<int&>(a));//因为a是const int类型
        int & ra = const_cast<int&>(a);
        ra = 200;
        cout<<"a = "<<a<<" ra= "<<ra<<endl;
        cout<<"&a = "<<&a<<" ra = "<<&ra<<endl;
        /*
        a = 19 ra = 200
        &a = 0x... 不一样
        */
    }
    

    用来移除对象的常量性(cast away the constness)使用 const_cast 去除 const 限定的目的不是为了修改它的内容,使用 const_cast 去除 const 限定,通常是为了函数能够接受这个实际参数。
    可以改变 const 自定义类的成员变量,但是对于内置数据类型,却表现未定义行为 .

    const 常变量

    #defined N 200 //宏,在预处理的阶段发生了替换
    const int a = 100;//编译阶段发生了替换
    //const 永远不会发生改变
    

    命名空间(namespace scope)

    //全局就是无名空间
    int v = 55;
    int main()
    {
        int *p = &v;//访问全局的
        int v =5;
        cout<<v<<endl;//5
        cout<<*p<<endl;//55
    
        cout<<::v<<endl;//::作用域运算符,前面要命名空间,平常调配用的函数之前省略::
        
        return 0;
    }
    
    

    namespace 是对全局命名空间的再次划分

    #include<iostream>
    using namespace std;
    namespace Spac{
        int a;//全局变量 
        struct Stu{};//数据类型 
        void func();//函数 
        namespace//其它命名空间 
    }
    

    使用:

    #include<iostream>
    using namespace std;
    namespace Space {
        int x;
        int y;
    }
    namespace Other {
        int x;
        int y;
    }
    int main()
    {
        Space::x = 200;//这种与本地的不会冲突
        cout<<Space::x<<endl;//200
    
        using Space::x;//在这作用域内的x都是Space命名空间中的x
        x = 20;
        cout<<x<<endl;
    
        using Space Space;//直接把Space这个命名空间打开
        x = 20;
        y = 30;
    
    
        return 0;
    }
    

    各种之间冲突解决

    利用最小单位的作用域块

    #include<iostream>
    using namespace std;//标中库空间命名
    namespace Space {
        int x;
        int y;
    }
    namespace Other {
        int x;
        int y;
    }
    int main()
    {
        {
            using Space Space;
            x = 20;
            y = 30;
        }
        {
            using Space Other;
            x = 50;
            y = 70;
        }
        int x,y;
    
        return 0;
    }
    

    支持嵌套

    namespace Space {
        int x;
        int y;
        namespace Other {
            int m;
            int n;
        }
    }
    int main()
    {
        using namespace Space::Other;//使用Other命名空间中的变量,不建议嵌套
        m = 30;
        return 0;
    }
    

    协同开发中的使用

    namespace Space {
        int x;
    }
    namespace Space {
        int y;
    }//命名空间相同会自动合并
    int main()
    {
        using namespace Space;
        x = 10;
        y = 20;
        return 0;
    }
    
    

    系统string类

    string是一个类而非关键字,初始化比较灵活(类似js中var)

    string s = "assassin";//赋值
    string s2 = "assassin1";
    cout<<s2.size()<<endl;//大小
    string s3 = "wunworld";
    s3 += s2;//拼接
    if(s == s2)//比较 
        cout<<"s = s2"<<endl;
    else if(s > s2)
        cout<<"s > s2"<<endl;
    else
        cout<<"s < s2"<<endl;
    
    char buf[1024];
    strcpy(buf,s.c_str());
    //如果和字符连用时,一定用c_str(),返回的是char *类型
    //交换swap(string &s2)成员函数
    s.swap(s2);
    
    

    查找:

    int find(char c, int pos = 0);
    int find(char * s, int pos = 0);
    //返回下标值,没有找到返回-1,默认从 0 下标开找
    

    eg:

    string s = "assassin";
    int n = s.find("i",0);
    cout<<n<<endl;//6
    

    string 类型数组

    string sArray[10] = {
                            "0",
                            "1",
                            "22",
                            "333",
                            "4444",
                            "55555",
                            "666666",
                            "7777777",
                            "88888888",
                            "999999999",
    };
    for(int i=0; i<10; i++)
    {
        cout<<sArray[i]<<endl;
    }
    

    string 数组是高效的,如果用二维数组来存入字符串数组的话,则容易浪费空间,此时列数是由最长的字符串决定。如果用二级指针申请堆空间,依据大小申请相应的空间,虽然解决了内存浪费的问题,但是操作麻烦。用 string 数组存储,字符串数组的话,效率即高又灵活。

    学习C++的建议:
    1、在 C++中几乎不需要用宏,用 const 或 enum 定义显式的常量,用 inline 避免函数 调用的额外开销,用模板去刻画一族函数或类型,用 namespace 去避免命名冲突。
    2、不要在你需要变量之前去声明,以保证你能立即对它进行初始化。
    3、不要用 malloc,new 运算会做的更好。
    4、避免使用 void*、指针算术、联合和强制,大多数情况下,强制都是设计错误的指示器。
    5、尽量少用数组和 C 风格的字符串,标准库中的 string 和 vector 可以简化程序。
    6、更加重要的是,试着将程序考虑为一组由类和对象表示的相互作用的概念,而不是一堆数据结构和一些可以拨弄的二进制

  • 相关阅读:
    MongoDB的索引(六)
    DMZ原理与应用
    MongoDB的增、删、改、查操作(五)
    一分钟了解mongodb(转)
    mongodb-java-driver基本用法
    Mongodb相对于关系型数据库的优缺点(转)
    什么场景应该用 MongoDB(转)
    MongoDB使用场景和局限 (转)
    matlab7与win7不兼容
    sublime的使用
  • 原文地址:https://www.cnblogs.com/intelwisd/p/8506922.html
Copyright © 2011-2022 走看看