Chinaunix首页 | 论坛 | 博客
  • 博客访问: 987928
  • 博文数量: 158
  • 博客积分: 4380
  • 博客等级: 上校
  • 技术积分: 2367
  • 用 户 组: 普通用户
  • 注册时间: 2006-09-21 10:45
文章分类

全部博文(158)

文章存档

2012年(158)

我的朋友

分类: C/C++

2012-11-23 17:04:46

1:C++标准说:An allocation function shall be a class member function or a global function; a program is ill-formed if an allocation function is declared in a namespace scope other than global scope or declared static in global scope.
必须是全局函数或类成员函数,而不能是全局之外的名字空间或static全局函数。

2:new operator的行为
对于如下代码:
    foo* p = new(参数1,参数2,…… ) foo(……);
    ……其他代码……
    delete p;
编译器将生成如下代码:
    调用 p = operator new( size_t 需要的大小,参数1,参数2,…… ); // 这里有可能抛出std::bad_alloc,但无须在new operator中捕捉
    如果构造foo不会抛出异常 // 即foo的构造函数后面显式的声明了 throw()
        在p指向处构造foo(参数1,参数2,……);
        return p;
    否则
        try
        {
            在p指向处构造foo(参数1,参数2,……);
            return p;
        }
        catch(...)
        {
            调用 operator delete( void* p, 参数1,参数2,…… );
            throw;
        }
    ……其他代码……
    调用 operator delete( void* p );

从上面的描述可以看出两点:
    a. 除了第一个参数外,其它参数和 operator new 都相同的 operator delete 称为相匹配的 operator delete
    b. 相匹配的 operator delete 仅在 operator new 成功,对象构造失败时被调用。而其他地方则一直调用 operator delete( void* p )。
       (如果不这么设计的话,编译器得为每一个p绑定当初调用它的operator new相匹配的operator delete的地址,以及当初调用时的实参,汗!!! )

3:全局形式的operator new伪代码
void* operator new( size_t size ) // 包括其他形式
{
    if( 0 == size ) // 须要注意
        size = 1;

    while(1)
    {
        分配size字节内存;
        if(分配成功)
            return 指向内存的指针;

        new_handler globalhandler = set_new_handler(0);
        set_new_handler(globalhandler);

        if( globalhandler )
            (*globalhandler)();
        else
            throw std::bad_alloc();
    }
}
void operator delete( void* raw )
{
    if( 0 == raw ) // 须要注意
        return;
    ...
}
须要说明的是,编译器本身就隐含着一个 void* operator new( size_t ),所以重载全局operator new必须加其他参数以示区别。
一般重载分配函数时都会重载三个,分别是 void* operator new( size_t, …… ),void operator delete( void*, …… ),以及一般形式的 void operator delete( void* )。

4. set_new_handler的作用
    set_new_handler设置一个函数,此函数将在分配内存失败时被调用,见3中的代码。
    从3中的代码还能看得出,new_handler必须有主动退出的功能,否则就会导致operator new内部死循环。因此newhandler的一般形式是:
    void mynewhandler()
    {
        if( 有可能使得operator new成功(比如释放部分内存) )
        {
            做有可能使得operator new成功的事
            return;
        }
        // 主动退出
        或 abort/exit 直接退出程序
        或 set_new_handler(其他newhandler);
        或 set_new_handler(0)
        或 throw bad_alloc()或派生类 // 这一种比较好,不粗鲁的关闭程序,也不更改其他设置
    }
须要说明的是,没有类形式的set_new_handler,但这也无所谓,你可以自己写。(见《Effective C++ 2e》条款7)

5. 类形式的operator new伪代码:
struct base
{
    ...
    static void* operator new( size_t size );
    static void operator delete( void* raw );
};
void* base::operator new( size_t size )
{
    if( sizeof(base) != size ) // 须要注意
        return ::operator new(size);

    类似于3 // 注意“没有类形式的set_new_handler”
}
void base::operator delete( void* raw )
{
    if( sizeof(base) != size ) // 须要注意
    {
        ::operator delete(raw);
        return;
    }
    同3
}

阅读(1376) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

网友评论2012-11-23 17:05:58

ssbottle
为什么类形式的operator new必须是static的呢?

网友评论2012-11-23 17:05:44

zwp
重载为静态成员函数还是挺有用的。
不仅仅在一些内存泄漏上可以做一些检测,而且可以在跨模块使用导出类的时候确保可以做一些clone之类的操作。