• c++杂记(new)


    这些东西是平时遇到的, 觉得有一定的价值, 所以记录下来, 以后遇到类似的问题可以查阅, 同时分享出来也能方便需要的人, 转载请注明来自RingOfTheC[ring.of.the.c@gmail.com]

    1. new

        前提知识: 区分new和new操作符

        new 的过程 1. 调用new操作符获取内存

                        2. 在内存上执行构造函数

        其中, 第一步new操作符可以重载

        a.  c++中, new失败默认是抛出异常, 所以检查new返回的指针是否为NULL是没有意义的

             char* p = new char[12];

             if (p == NULL)  // 没意义, 如果new失败, 根本就不会走到这里来

                  /* ….. */

            正确的检查办法是:

             try{ char *p = new char[12]; /* …….. */ }

             catch(const bad_alloc& e) {/* ………. */}

        b.  如果想让new失败返回NULL指针而不抛异常, 可以使用nothrow方法,

            char* p = new (std::nothrow) char[12];

            if (p == NULL)  // 这下就是预期行为了, new失败了, 只是返回NULL指针

                /* …… */

        c.  在给定的内存上构造一个对象的方法, 注意四点:

            void* p = malloc(sizeof(T));  // 1. 自己手动分配内存, 当然可以不是堆上, 可以是栈上等

            if (p == NULL)

                 reuturn ;

            T* tp = new(p) T;               // 2. 显示调用构造函数

            /* 使用 */

            tp->~T();                           // 3. 必须显示调用析构函数

            free(tp);                             //  4. 释放内存, 如果需要的话

        d. 重载类的operator new时, 有一些比较灵活的做法, 你可以向operator new传递你想要的任何参数

            1.  struct T{

                   T* operator new(size_t size, size_t extern){

                        return ::malloc(size + extern);

                   }

                 }

                 T* p = new(15) T; // 这样调用, 上面的size = sizeof(T) , extern = 15

            2.  struct T{

                   T* operator new(size_t size, size_t extern, char* log){

                        return ::malloc(size + extern);

                   }

                 }

                 T* p = new(15, “hi , alloc”) T;  // 这样调用, 上面的size = sizeof(T), extern = 15, log = "hi , alloc"

             从上面可以看出, 重载operator new的时候, 函数的第一个参数固定不变的是重载了new操作符的对象的大小, 除了这个参数, 其它可以自定义:), 这个很灵活

    2. delete没有new那么多的魔法

         除了正常的delete, 类的重载operator delete可以有 operator delete(void* p)和operator delete(void* p, size_t size)两个形式, 其中size是该类的size大小, 借此可以证明 "delete一个父类指针, 但这个指针实际上是指向其子类的造成内存回收问题"

         struct T{

             int a;int b;

             void* operator new(size_t size) {  return ::operator new(size);  }

             void  operator delete(void* p, size_t size)  {  ::operator delete(p);  }

         }

         struct D : T{

             int c;

         }

         测试程序:

         T* p = new D;   // 这里跟进去operator new参数是12 及sizeof(D)

         delete T;          // 这里跟入去会发现operator delete的第二参数是8及sizeof(T), 明显内存泄露了, 所以大家一再强调, 做父类的最好把自己定义一个虚的析构函数, 修改后如下:

         struct T{

             int a;int b;

             void* operator new(size_t size) {  return ::operator new(size);  }

             void  operator delete(void* p, size_t size)  {  ::operator delete(p);  }

             virtual ~T(){}

         }

         struct D : T{

             int c;

         }

         测试程序:

         T* p = new D;   // 这里跟进去operator new参数是12 及sizeof(D)

         delete T;          // 这里跟入去会发现operator delete的第二参数是8及sizeof(D), 是我们想要的

         好了, 举这个例子不是为了说明父类和子类这些内存问题, 而是为了说明, delete有这样一个参数, 而且这个参数很有用, 很能说明问题, 可以用来检测错误, log统计等.

  • 相关阅读:
    HttpWebRequest的GetResponse或GetRequestStream偶尔超时 + 总结各种超时死掉的可能和相应的解决办法
    如何制作一个没有任何窗体的,隐藏在后台的程序
    ActiveMQ持久化消息(转)
    ActiveMQ发布订阅模式(转)
    .Net平台下ActiveMQ入门实例(转)
    SQL重复记录查询的几种方法(转)
    XML 解析中,如何排除控制字符
    事件委托
    margin重叠
    office web apps 部署-搭建域控服务器
  • 原文地址:https://www.cnblogs.com/ringofthec/p/new_delete.html
Copyright © 2020-2023  润新知