c++对象模型25

malloc 分配0字节

void* p = malloc(0);
分配0字节 所以不要搞多余内存的copy 比如:
char *q = (char *)p;
strcpy_s(q, 100 , "qweqweqweqw");
这就很危险 因为已经在操作不属于分配的内存
free(p);  
这时候程序已经崩溃

所以malloc(0)返回的是一个有效的内存地址 你也不要去修改这个内存 
所以就不要这么写 没意义

new类对象时加不加括号的差别:

class A{
public:
    A(){};
    int m; 
}

int main(){
    A *pa = new A();  
    A *pa = new A;
    // 如果是个空类 ,那么两种写法没有区别
     // 带括号的初始化会把一些和成员变量有关的内存清0
    //  如果有构造函数 则这两个写法没有区别
}


-------------------------------------------------

int *p3 = new int;  //  初值随机
int *p4 = new int();  //  初值0
int *p5 = new int(100);  // 100;

-------------------------------------------------

new 干了什么?
    new 是操作符
    两件事:operator new()         (调用malloc
    一个是调用了类的构造函数    (有就调用 没有就不调用

delete:    
    调用析构函数
    然后调用operator  delete      (调用free

new/delete 和malloc /free 有什么区别
    new/delete 是操作符调用malloc/free    malloc /free 是关键字
    new/delete 会调用析构函数和构造函数


-------------------------------------------------

malloc 调用更底层和操作系统相关的函数

分配内存这个事 不是简单的分配四个字节 而是在四个字节周围 编译器做了很多处理 比如记录分配出去的字节数等等
造成了浪费。尤其时多次分配小的内存

内存池:
    减少malloc次数,节约对内存的浪费
    
    
class A {
public:
    static void* operator new(size_t);
    static void operator delete(void* phead);
    static int m_iCout;   //  统计多少次new
    static int m_iMallocCout;   // 每malloc一次 ++;
private:
    A* next;  // 指向下一个对象
    static A* m_FreePosi;   // 总是指向一块可以分配出去的内存首地址
    static int m_sTrunkCout;  // 一次分配多少倍的该类内存
};
int A::m_iCout = 0;
int A::m_iMallocCout = 0;
A* A::m_FreePosi = nullptr;
int A::m_sTrunkCout = 5;  // 一次分配五倍的该类内存作为内存池大小

void* A::operator new(size_t size) { 
    A* tmplink;
    if (m_FreePosi == nullptr) {
        // 为空 申请内存
        size_t realsize = m_sTrunkCout * size;
        m_FreePosi = reinterpret_cast<A*>(new char[realsize]);
        tmplink = m_FreePosi;
        for (; tmplink != &m_FreePosi[realsize - 1]; ++tmplink) {
            // 链表 方便追踪
            tmplink->next = tmplink + 1;
        }
        tmplink->next = nullptr; 
        // 将最后一个tmplink 指向空
        ++m_iMallocCout;
    }
    tmplink = m_FreePosi; 
    m_FreePosi = m_FreePosi->next;  // 将m_FreePosi向下偏移 返回新的对象
    // 当m_FreePosi为nullptr以后就重新申请内存
    ++m_iCout;
    // 
    return m_FreePosi;
}
void A::operator delete(void * phead) {
    (static_cast<A*>(phead))->next = m_FreePosi;
    // 把当前对象的next指向最新的m_FreePosi
    m_FreePosi = static_cast<A*>(phead);
    //  这个对象重复使用
    //  也就是说虽然说是delete但并没有调用释放内存
    //new char[realsize] 并没有释放 
    // 析构函数倒是被调用

}

嵌入式指针:

一般应用在内存池相关的代码中: 成功使用其纳入是指针有个前提条件
类对象的sizeof不能小于4字节

借用对象原本的内存寻找下一个内存地址的手段

定位new;
在内存已经分配好的基础上 初始化已经新的对象  ( 调用构造函数
class A(){
public:
    A(){}
    A(int value):A(value){}
    ~A(){}
}

void *myPoint = (void *)new char[sizeof(A)];
A *myAobj  = new (myPoint) A();

这里并不会分配额外的内存

// 带参数版本
void *myPoint = (void *)new char[sizeof(A)];
A *myAobj2  = new (myPoint) A(2);

//delete myAobj;  
//delete myAobj2;

myAobj->~A();
myAobj2->~A();

delete[](void *)myAobj;
delete[](void *)myAobj2;


具体汇编代码
A *myAobj2  = new (myPoint) A(2);
    operator new()   //  这里并没有malloc  
    A::A() 


重载定位new
void *operator new(size_t size, void *phead){
    return phead
}


拷贝构造函数的临时性对象
class A{
public:
    A(){cout << "拷贝构造函数被执行" <<endl;}
    A(const &A tmpobj) {cout << "A::A()拷贝构造函数被执行" <<endl;}
    ~A() {cout << "析构函数被执行" <<endl;}
}

A operator +(const A& obj1, const A& obj2){
    A tmpobj;
    //...
    return tmpobj;
}

int main(){
    A myobj1;
    A myobj2;
    A result = myobj1 + myobj2;
}

//
拷贝构造函数被执行        //A myobj1;
拷贝构造函数被执行        //A myobj2;
拷贝构造函数被执行        //A tmpobj;
A::A()拷贝构造函数被执行       //return tmpobj; 产生一个临时对象,把tmpobj对象内容通过调用拷贝构造函数
                            把内容拷贝给临时对象 然后返回这个临时对象, 这个返回的临时对象直接构造到了result中
析构函数被执行     //      A tmpobj;
析构函数被执行        //     A myobj1;
析构函数被执行        //     A myobj2;
析构函数被执行        //     A result;

class A{
public:
    A(){cout << "拷贝构造函数被执行" <<endl;}
    A(const &A tmpobj) {cout << "A::A()拷贝构造函数被执行" <<endl;}
    ~A() {cout << "析构函数被执行" <<endl;}
    A& operator=(const A& tmpobj) { 
        cout << "拷贝赋值运算符" <<endl;
        return *this
    }
}

A operator +(const A& obj1, const A& obj2){
    A tmpobj;
    //...
    return tmpobj;
}

int main(){
    A myobj1;
    A myobj2;
    A result;
    result = myobj1 + myobj2;
}


拷贝构造函数被执行        //A myobj1;
拷贝构造函数被执行        //A myobj2;
拷贝构造函数被执行        //A result;
拷贝构造函数被执行        //A tmpobj;
A::A()拷贝构造函数被执行       //return tmpobj; 产生一个临时对象,把tmpobj对象内容通过调用拷贝构造函数
                            把内容拷贝给临时对象 然后返回这个临时对象
析构函数被执行     //      A tmpobj;
拷贝赋值运算符    //  将临时对象拷贝赋值给 result;
析构函数被执行    // 释放这个临时对象
析构函数被执行
析构函数被执行
析构函数被执行

class A{
public:
    A(){cout << "拷贝构造函数被执行" <<endl;}
    A(const &A tmpobj) {cout << "A::A()拷贝构造函数被执行" <<endl;}
    ~A() {cout << "析构函数被执行" <<endl;}
    A& operator=(const A& tmpobj) { 
        cout << "拷贝赋值运算符" <<endl;
        return *this
    }
}

A operator +(const A& obj1, const A& obj2){
    A tmpobj;
    //...
    return tmpobj;
}

int main(){
    A myobj1;
    A myobj2;
    myobj1 + myobj2;
}

构造函数
构造函数
构造函数
拷贝赋值运算符    // 临时对象
析构函数            // 析构 tmpobj
析构函数            //  析构临时对象

const char *p = (string("123") + string("456")).c_str();
// 右值产生的临时对象在本行结束后就会被销毁 所以这个代码有问题

string aaa = string("123") + string("123");
const char *q = aaa.c_str();

const string &aaa = string("123") + string("123");

----------------------------------------

模板及其实例化
模板在其调用的时候才会推断具体的类型 (vs2017
如果没有使用这个模板则不会推断

template<class T>
class ATL {
public:
    enum ECURRSTATUS {
        E_CS_Busy,
        E_CS_Free
    };

public:
    T mi, mj;
    ATL(T tmpi = 0,T tmpj = 0) {
        mi = tmpi;
        mj = tmpi;
    }
};


ATL<int>::ECURRSTATUS n;
代码执行到这里依旧没有推断类型
n = ATL<int>::E_CS_Busy;
代码到这里也只是使用了ATL的int类型 也就是只使用了枚举类型
ATL<int>::ECURRSTATUS 编译器把这个只当作普通的枚举类型

template<class T>
class ATL {
public:
    enum ECURRSTATUS {
        E_CS_Busy,
        E_CS_Free
    };
    static int m_sti;

public:
    T mi, mj;
    ATL(T tmpi = 0,T tmpj = 0) {
        mi = tmpi;
        mj = tmpi;
    }
};

template <class T> int ATL<T>::m_sti = 12;
int main(){
    cout <<ATL<int>::m_sti <<endl;

}

这里的类型也只是用到int并不涉及具体的类型推断

-------------------------------------------


template<class T>
class ATL {
public:
    enum ECURRSTATUS {
        E_CS_Busy,
        E_CS_Free
    };
    static T m_sti;

public:
    T mi, mj;
    ATL(T tmpi = 0,T tmpj = 0) {
        mi = tmpi;
        mj = tmpi;
    }
};
template <class T> T ATL<T>::m_sti = 12;
int main(){
    cout <<ATL<int>::m_sti <<endl;

}

template <class T> T ATL<T>::m_sti = 12;这里的T只有在具体给定这个模板类型 并且在调用的时候
编译器才会确定这个语法是否合格


ATL<int> *pobj = NULL; 
这种写法不会实例化具体的类


const ATL<int> &interATL = 0;
实例化了类模板
如果现在这个类中有函数 但是并没有具体调用则这个函数不会被实例化

如果这个类模板是在头文件中
那么在源文件中使用类模板就会初始化 不管到底调用不调用
在多个obj文件中可能产生多个重复的类模板对应的具体实例化类
但是在链接的时候直会保留一个ATL<int>类的实体,其余被忽略掉


虚函数也不会出现例外。即使没有被调用 也会被实例化,
因为有虚函数 编译器就会产生虚函数表  既然需要这个虚函数的地址 所以就必须实例化虚函数

显式实例化:
    template class ATL<int>
    显式实例化语法 会把类模板中 的所有内容都实例化出来,但是这种写法 铺展浪费
    
template void ATL<int>::func();  具体实例化哪个函数
但是这并没有实例化ATL<int>本身 只是单独实例化具体的哪个函数

如何实现一个不能被继承的类
c++11   final

友元函数 + 虚继承 = 不能被继承的类
// 问题 :虚继承消耗大

class A{
private:
    A(){};
    int m;
}

class B:virtual public A{
     
}
为什么不能被继承?
虚继承的爷爷类最终是由孙子类调用
只有互为友元类才能调用private  所以孙子类无法实例化爷爷类 所以导致无法继承


类外调用私有虚成员函数
class A{
private:
    virtual void virfunc(){
    }
}
A obj;
(reinterpret_cast<void(*)())>(**int(**)(&obj)))();

就一个虚函数
类的地址跟虚函数指针的首地址相同
**int(**)  指针的指针 也就是虚函数表指针指向虚函数的地址
然后转换成void (*) ()  函数指针
然后最外面()  调用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值