• malloc free使用规范


    malloc free使用规范

    A、申请了内存空间后,必须检查是否分配成功。

    B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。

    C、这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会

    出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。

    D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一

    些编译器的检查。

    new
    A* a = new A
    有人也称newnew operator,区别于下面的operator new
    这里分为三步:

    1. 分配内存
    2. 调用A()构造对象
    3. 返回分配指针。

    事实上,分配内存这一操作就是由operator new(size_t)来完成的,如果类A重载了operator new,那么将调用A::operator new(size_t ),
    否则调用全局::operator new(size_t ),后者由C++默认提供。因此前面的步骤也就是:

    • 调用operator new (sizeof(A))
    • 调用A:A()
    • 返回指针
    /**
    *  ::operator new()源代码
    *  主要就是调用一个malloc,若调用不成功,调用_callnewh
    */
    void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
    {       // try to allocate size bytes
            void *p;
            while ((p = malloc(size)) == 0)
                    if (_callnewh(size) == 0)
                    {       // report no memory
                    static const std::bad_alloc nomem;
                    _RAISE(nomem);
                    }
     
            return (p);
    }
    

    delete()

    1. 调用一个对象的析构函数,
    2. 调用operator delete
    /**
    *  operator delete()源代码
    *  
    */
    void operator delete(
            void *pUserData
            )
    {
            _CrtMemBlockHeader * pHead;
    
            RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
    
            if (pUserData == NULL)
                return;
    
            _mlock(_HEAP_LOCK);  /* block other threads */
            __TRY
    
                /* get a pointer to memory block header */
                pHead = pHdr(pUserData);
    
                 /* verify block type */
                _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
    
                _free_dbg( pUserData, pHead->nBlockUse );
    
            __FINALLY
                _munlock(_HEAP_LOCK);  /* release other threads */
            __END_TRY_FINALLY
    
            return;
    }
    

    new[]作用
    调用operator new分配空间。调用N次构造函数分别初始化每个对象。

    /**
    *  new[]源代码
    *  
    */
    void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc)
        {   // try to allocate count bytes for an array
        return (operator new(count));
        }
    

    delete[]作用
    调用N次析构函数清理对象,调用operator delete释放空间。
    注意内存泄漏

    /**
    *  delete[]源代码
    *  
    */
    void operator delete[]( void * p )
    {
        RTCCALLBACK(_RTC_Free_hook, (p, 0))
    
        operator delete(p);
    }
    

    placement new
    Ctor&Dtor:构造函数不能被直接调用,析构函数可以被直接调用,想要直接调用构造函数要用placement new
    A *p=new (mem) A
    所谓placement new就是在用户指定的内存位置上构建新的对象,这个构建过程不需要额外分配内存,只需要调用对象的构造函数即可。
    没有所谓的placement delete,因为placement new根本没有分配memory
    或者称呼与placement new对应的operator delete为placement delete
    placement new的好处:
    1)在已分配好的内存上进行对象的构建,构建速度快。
    2)已分配好的内存可以反复利用,有效的避免内存碎片问题。

    /**
    *  placement new实例
    *
    */
    #include <iostream>
    using namespace std;
     
    class A
    {
    public:
    	A()
    	{
    		cout << "A's constructor" << endl;
    	}
     
     
    	~A()
    	{
    		cout << "A's destructor" << endl;
    	}
    	
    	void show()
    	{
    		cout << "num:" << num << endl;
    	}
    	
    private:
    	int num;
    };
     
    int main()
    {
    	char mem[100];
    	mem[0] = 'A';
    	mem[1] = '';
    	mem[2] = '';
    	mem[3] = '';
    	cout << (void*)mem << endl;
    	A* p = new (mem)A;
    	cout << p << endl;
    	p->show();
    	p->~A();
    	getchar();
    }
    

    (1)用定位放置new操作,既可以在栈(stack)上生成对象,也可以在堆(heap)上生成对象。如本例就是在栈上生成一个对象。
    (2)使用语句A* p=new (mem) A;定位生成对象时,指针p和数组名mem指向同一片存储区。所以,与其说定位放置new操作是申请空间,还不如说是利用已经请好的空间,真正的申请空间的工作是在此之前完成的。
    (3)使用语句A *p=new (mem) A;定位生成对象时,会自动调用类A的构造函数,但是由于对象的空间不会自动释放(对象实际上是借用别人的空间),所以必须显示的调用类的析构函数,如本例中的p->~A()。
    (4)如果有这样一个场景,我们需要大量的申请一块类似的内存空间,然后又释放掉,比如在在一个server中对于客户端的请求,每个客户端的每一次上行数据我们都需要为此申请一块内存,当我们处理完请求给客户端下行回复时释放掉该内存,表面上看者符合c++的内存管理要求,没有什么错误,但是仔细想想很不合理,为什么我们每个请求都要重新申请一块内存呢,要知道每一次内从的申请,系统都要在内存中找到一块合适大小的连续的内存空间,这个过程是很慢的(相对而言),极端情况下,如果当前系统中有大量的内存碎片,并且我们申请的空间很大,甚至有可能失败。为什么我们不能共用一块我们事先准备好的内存呢?可以的,我们可以使用placement new来构造对象,那么就会在我们指定的内存空间中构造对象。

    嵌入式指针
    请使用 1 == p
    而不是 p == 1
    对于单纯常量,最好以const对象或enums替换#defines。
    对于形似函数的宏(macros),最好改用inline函数替换#defines。

    尽可能使用const:

    const语法虽然变化多端,但并不莫测高深。
    如果关键字const出现在星号左边,表示被指物是常量;
    如果出现在星号右边,表示指针自身是常量;
    如果出现在星号两边,表示被指物和指针两者都是常量。

    令operator=返回一个reference to *this

    https://blog.csdn.net/nodeathphoenix/article/details/38146421

    宁以pass-by-reference-to-const替换pass-by-value

  • 相关阅读:
    Agreementhasbeenupdated--EditPhoneNumber
    android 6.0之后动态获取权限
    appstore加速审核通道
    ListView多种item注意以及自己出现的莫名其妙的错误
    2020-10-15:mysql的双1设置是什么?
    2020-10-14:Redisson分布式锁超时自动释放,会有什么问题?
    2020-10-13:hash与B+tree的区别?
    2020-10-12:在做分布式集群时候一般会产生什么问题?
    2020-10-11:一条sql语句执行时间过长,应该如何优化?从哪些方面进行优化?
    2020-10-10:OOM都有哪些,说出几种?
  • 原文地址:https://www.cnblogs.com/CSE-kun/p/14492249.html
Copyright © 2020-2023  润新知