第一讲:primitives
四种内存分配与释放基本构件之 new/delete expression
1、内存申请2、内存释放3、模拟编译器直接调用构造和析构函数 Array new 第二讲:malloc/free第三讲:std::allocator第四讲:other allocators第五讲:loki::allocator
第一讲:primitives 四种内存分配与释放
在编程时可以通过上图的几种方法直接或间接地 *** 作内存。下面将介绍四种C++内存 *** 作方法:
1.::operator new()调用malloc,::operator delete()调用free
2.通常可以使用malloc和new来分配内存,当然也可以使用::operator new()(是一个全局函数)和分配器allocator来 *** 作内存,下面将具体介绍这些函数的使用方法。对于不同的编译器,其allocate函数的接口也有所不同:
对于GNU C,不同版本又有所不同:
这张图中的__gnu_cxx::__pool_alloc().allocate()对应于上张图中的allocator().allocate()。
通过malloc和new分配内存、通过free和delete释放内存是十分常用的,通过::operator new *** 作内存比较少见,allocator分配器 *** 作内存在STL源码中使用较多,对于不同的编译环境使用也有所不同。下面这个例子是基与VS2019环境做测试的
#include#include #include //std::allocator using namespace std; namespace jj01 { void test_primitives1() { cout << "ntest_primitives().......... n"; void* p1 = malloc(512);//512 bytes free(p1); complex * p2 = new complex ;//one object一个单元 delete p2; void* p3 = ::operator new(512);//512 bytes ::operator delete(p3); //以下使用 C++ 標準庫提供的 allocators。 //其接口雖有標準規格,但實現廠商並未完全遵守;下面三者形式略異。 #ifdef _MSC_VER //VC接口 //以下兩函數都是 non-static,定要通過 object 調用。以下分配 3 個 ints. //allocator ()临时对象 int* p4 = allocator ().allocate(3, (int*)0); p4[0] = 666; p4[1] = 999; p4[2] = 888; cout << "p4[0] = " << p4[0] << endl; cout << "p4[1] = " << p4[1] << endl; cout << "p4[2] = " << p4[2] << endl; //还内存的时候还要把当初分配内存大小表明,这种事情只有容器可以做到 allocator ().deallocate(p4, 3); #endif // _MSC_VER } } int main(void) { jj01::test_primitives1(); return 0; }
test_primitives().......... p4[0] = 666 p4[1] = 999 p4[2] = 888
可见 int* p4 = allocator().allocate(3, (int*)0) *** 作成功申请了三个int的空间。
基本构件之 new/delete expression 1、内存申请
上面这张图揭示了new *** 作背后编译器做的事:
1、第一步通过operator new() *** 作分配一个目标类型的内存大小,这里是Complex的大小;
2、第二步通过static_cast 将得到的内存块强制转换为目标类型指针,这里是Complex*
3、第三版调用目标类型的构造方法,但是需要注意的是,直接通过pc->Complex::Complex(1, 2)这样的方法调用构造函数只有编译器可以做,用户这样做将产生错误。
值得注意的是,operator new() *** 作的内部是调用了malloc()函数。
2、内存释放
同样地,delete *** 作第一步也是调用了对象的析构函数,然后再通过operator delete()函数释放内存,本质上也是调用了free函数。
#include#include #include //std::allocator using namespace std; namespace jj02 { class A { public: int id; A():id(0) { cout << "default ctor. this=" << this << " id=" << id << endl; } A(int i):id(i) { cout << "ctor. this=" << this << " id=" << id << endl; } ~A() { cout << "dtor. this=" << this << " id=" << id << endl; } }; void test_call_all_ctor_directly() { cout << "ntest_call_ctor_directly().......... n"; string* pstr = new string; cout << "str= " << *pstr << endl; //! pstr->string::string("jjhou"); //[Error] 'class std::basic_string ' has no member named 'string' //! pstr->~string(); //crash -- 其語法語意都是正確的, crash 只因為上一行被 remark 起來嘛. cout << "str= " << *pstr << endl; A* pA = new A(1); cout << pA->id << endl; //1 pA->A::A(3); cout << pA->id << endl; //! pA->A::A(3); //in VC6 : ctor. this=000307A8 id=3 //in GCC : [Error] cannot call constructor 'jj02::A::A' directly A::A(5); //! A::A(5); //in VC6 : ctor. this=0013FF60 id=5 // dtor. this=0013FF60 //in GCC : [Error] cannot call constructor 'jj02::A::A' directly // [Note] for a function-style cast, remove the redundant '::A' cout << pA->id << endl; //in VC6 : 3 //in GCC : 1 delete pA; //simulate new void* p = ::operator new(sizeof(A)); cout << "p=" << p << endl; //p=000307A8 pA = static_cast(p); pA->A::A(2); //! pA->A::A(2); //in VC6 : ctor. this=000307A8 id=2 //in GCC : [Error] cannot call constructor 'jj02::A::A' directly cout << pA->id << endl; //in VC6 : 2 //in GCC : 0 //simulate delete pA->~A();//先析构 ::operator delete(pA);//free()再释放内存 } } int main(void) { jj02::test_call_all_ctor_directly(); return 0; }
test_call_ctor_directly().......... str= str= ctor. this=0149D1C8 id=1 1 ctor. this=0149D1C8 id=3 3 ctor. this=0118FB48 id=5 dtor. this=0118FB48 id=5 3 dtor. this=0149D1C8 id=3 p=0149FED0 ctor. this=0149FED0 id=2 2 dtor. this=0149FED0 id=2Array new 第二讲:malloc/free 第三讲:std::allocator 第四讲:other allocators 第五讲:loki::allocator
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)