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

原文地址:https://www.cnblogs.com/CSE-kun/p/14492249.html