C++ 应用程序,应用 memory 的路径

C++ memory primitives

调配开释类属可否重载
malloc()free()C 函数不可
newdeleteC++ 表达式不可
::operator new()::operator delete()C++ 函数
allocator<T>::allocate()allocator<T>::deallocateC++ 规范库可自在设计并予以搭配任何容器
void *p1 = malloc(512); // 512 bytesfree(p1)
complex<int>* p2 = new complex<int>;    // one objectdelete p2;
void *p3 = ::operator new(512); // 512 bytes::operator delete(p3);
// 以下应用 C++ 规范库提供的 allocators// 其接口虽有规范规格,但实现厂商并未齐全恪守;上面三种模式略异#ifdef _MSV_VER    // 以下两个函数都是 no-static, 要通过 object 调用。    // 调配 3 个 ints    int *p4 = allocator<int>().allocate(3, (int*)0);    // 对应规范库分配器的第二个参数    allocator<int>().deallocate(p4, 3);#endif#ifdef __BORLANDC__    // 以下两个函数都是 no-static, 要通过 object 调用。    // 调配 5 个 ints    int *p4 = allocator<int>().allocate(5); // 同样蕴含第二个参数,但申明处有默认值,因而调用处可不写    allocator<int>().deallocate(p4, 5);#endif#ifdef __GNUC__ // 晚期版本的实现, 2.9    // 以下两个啊含混都是 static, 可通过全名调用。    // 调配 512 bytes    void *p4 = alloc::allocate(512);    alloc::deallocate(p4, 512);#endif
#ifdef __GNUC__ // 古代版本的实现, 4.9    // 以下两个函数都是 no-static,要通过 object 调用。    // 调配 7 个 ints    void *p4 = allocator<int>().allocate(7);    allocator<int>().deallocate((int*)p4, 7);        // 以下两个函数都是 no-static,要通过 object 调用。    // 调配 9 个 ints    void *p4 = __gnu_cxx::pool_alloc<int>().allocate(9);    __gnu_cxx::pool_alloc<int>.deallocate((int*)p4, 9);#endif

new expression (new 背地的行为)

Complex *pc = new Complex(1, 2);编译器转换为 ==>>Complex *pc;try {    /* 1 */ void mem = operator new (sizeof(Complex));  // allocate 申请内存空间    /* 2 */ pc = static_cast<Complex*>(mem);            // cast 类型转换    /* 3 */ pc->Complex::Complex(1, 2);                 // construct 调用构造函数    // 留神:只有编译器才能够像下面那样间接呼叫 ctor}catch (std::bad_alloc) {    // 若 allocation 失败,就不执行 constructor }
注:
  • 申请内存可能会失败,因而引入 try...catch...
  • new 做两个动作

    • 申请内存
    • 调用构造函数
  • 欲间接调用 ctor, 可调用 placement new, new(p)Complex(1, 2)
// ...\vc98\crt\src\newop2.cpp (其中一个实现版本)void *operator(size_t size, const std::nothrow_t &_THROW0()){    // try to allocate size bytes    void *p;    while ((p = malloc(size)) == 0)    {        // buy more memory or return null pointer        __TRY_BEGIN        if (_callnewh(size) == 0) break;        _CATCH(std::bad_alloc)  return (0);        _CATCH_END    }}
注:
  • std::nothrow_t 构造用作 new 运算符的函数参数,批示该函数应返回空指针以报告调配失败,而不是引发异样(struct std::nothrow_t{})
  • 当内存申请失败,_callnewh 调用 typedef void (*new_handler)(); new_handler set_new_handler(new_handler p) throw() 设置的函数,使得咱们有机会开释掉咱们认为能够开释的内存空间

delete expression (delete 背地的行为)

Complex *pc = new Complex(1, 2);delete pc;编译器转换为 ==>>pc->~Complex();         // 调用析构函数operator delete (pc);   // 开释内存
注:delete 的两个动作
  • 调用析构函数
  • 开释内存

    // ...\vc98\crt\src\delop.cpp (其中一个实现版本)void __cdelc operator delete(void *p) __THROW0(){// free an allocated objectfree(p);}

    Ctor(构造函数) & Dtor(析构函数) 间接调用

    #include <iostream> 

using namespace std;

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_1()
{

cout << endl << "test_1" << endl;A *pA = new A(1);cout << pA->id << endl;delete pA;

}

// simulate new
void test_2()
{

cout << endl << "test_2" << endl;void *p = ::operator new(sizeof(A));    cout << "p=" << p << endl;A *pA = static_cast<A*>(p);cout << pA->id << endl;pA->~A();::operator delete(pA);

}

void test_3()
{

cout << endl << "test_3" << endl;A *pA = new A(3);cout << pA->id << endl;// pA->A::A(3);    // [Error] cannot call constructor 'A::A' directly// A::A(5);        // [Error] cannot call constructor 'A::A' directlypA->~A();        // 编译无谬误, 析构函数被调用 delete pA;

}

int main()
{

test_1();test_2();test_3();return 0;    

}

输入:[编译器 gnu 4.9,2]

test_1 // 结构、析构函数被调用,一切正常
ctor. this=0x781510 id=1
1
dtor. this=0x781510 id=1

test_2 // 构造函数未被调用
p=0x781510
7870992 // id 为内存中的随机值
dtor. this=0x781510 id=7870992 // 析构函数可被间接调用,但存在危险!!

test_3
ctor. this=0x781510 id=3 // 构造函数被调用
3
dtor. this=0x781510 id=3 // 析构函数被间接调用,但存在危险!!
dtor. this=0x781510 id=3 // 析构函数被 delete 时调用

> 注:* 语法上构造函数不可被间接调用;编译器收回谬误* 语法上析构函数可被间接调用;编译通过;但不能够这样应用,比方析构函数中须要开释系统资源时,析构函被屡次调用,资源也将被开释屡次,行为未定义* 理论应用时,构造函数、析构函数都不应该间接调用