C++Effective C++

【Effective C++(8)】定制new和delete

2018-01-09  本文已影响36人  downdemo

operator new
operator delete
set_new_handler

49 了解new-handler的行为

namespace std {
    typedef void(*new_handler)();
    new_handler set_new_handler(new_handler new_p) noexcept;
}
#include <iostream>
#include <new>

void handler()
{
    std::cerr << "Unable to satisfy request for memory\n";
    std::abort();
}

int main()
{
    std::set_new_handler(handler);
    while (true) new char[1024*1024*1024]; // 循环分配1GB内存
    // 分配失败时调用handler()函数
};
#include <iostream>
#include <new>
 
void handler()
{
    std::cout << "Memory allocation failed, terminating\n";
    std::set_new_handler(nullptr); // 分配失败则抛std::bad_alloc异常
}
 
int main()
{
    std::set_new_handler(handler);
    try {
        while (true) {
            new int[100000000ul];
        }
    } catch (const std::bad_alloc& e) {
        std::cout << e.what() << '\n';
    }
}
class A {
public:
    static std::new_handler set_new_handler(std::new_handler p) noexcept;
    static void* opreator new(std::size_t size) throw(std::bad_alloc);
private:
    static std::new_handler currentHandler;
};
// static成员必须在class定义式之外被定义
std::new_handler A::currentHandler = 0;
std::new_handler A::set_new_handler(std::new_handler p) noexcept
{
    std::new_handler oldHandler = currentHandler;
    currentHandler = p;
    return oldHandler;
}
class A {
public:
    static std::new_handler set_new_handler(std::new_handler p) noexcept;
    static void* opreator new(std::size_t size) throw(std::bad_alloc);
private:
    static std::new_handler currentHandler;
};
std::new_handler A::currentHandler = 0;
std::new_handler A::set_new_handler(std::new_handler p) noexcept
{
    std::new_handler oldHandler = currentHandler;
    currentHandler = p;
    return oldHandler;
}

class NewHandlerHolder {
public:
    explicit NewHandlerHolder(std::new_handler nh) // 取得目前new-handler
    : handler(nh) {}

    ~NewHandlerHolder() // 释放它
    { std::set_new_handler(handelr); }

    NewHandlerHolder(const NewHandlerHolder&) = 0; // 阻止copying
    NewHandlerHolder& operator=(const NewHandlerHolder&) = 0;
private:
    std::new_handler handlder; // 记录下来
};

// 这样operator new的实现就很简单
void* A::operator new(std::size_t size) throw(std::bad_alloc)
{
    NewHandlerHolder h(std::set_new_handler(currentHandler)); // A安装new-handler
    // 返回值为A之前拥有的currentHandler,即旧的指针被传给NewHandlerHolder存储
    return ::operator new(size); // 分配内存或者抛出异常
}; // NewHandlerHolder执行析构函数,安装存储的旧指针,从而恢复global new-handler

// A的用户应该类似这样使用其new-handling
void outOfMem(); // 函数声明,此函数在对象分配失败时被调用
A::set_new_handler(outOfMem); // 设定outOfMem为类的new-handling函数
A* p1 = new A; // 如果内存分配失败,调用outOfMem
std::string* ps = new std::string; // 如果内存分配失败,调用global new-handling函数
A::set_new_handler(0); // 设定类专属的new-handling函数为空
A* p2 = new A; // 如果内存分配失败,立刻抛出异常
template <typename T>
class NewHandlerSupport {
public:
    static std::new_handler set_new_handler(std::new_handler p) noexcept;
    static void* operator new(std::size_t size) throw(std::bad_alloc);
    ...
private:
    static std::new_handler currentHandler;
};

template <typename T>
std::new_handler NewHandlerSupport<T>::set_new_handler(std::new_handler p) noexcept
{
    std::new_handler oldHandler = currentHandler;
    currentHandler = p;
    return oldHandler;
}

template <typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size) throw(std::bad_alloc)
{
    NewHandlerHolder h(std::set_new_handler(currentHandlder));
    return ::operator new(size);
}

template <typename T>
std::new_handler NewHandlerSupport<T>::currentHandler = 0;

// 有了这个class template,为A添加set_new_handler就很容易了
class A::public NewHandlderSupport<A> {
    ...
    // 和先前一样,但不必声明set_new_handler或者operator new
};

50 了解new和delete的合理替换时机

static const int signature = 0xDEADBEEF;
typedef unsigned char Byte;
//这段代码还有若干小错误,详下
void* operator new(std::size_t size) throw(std::bad_alloc)
{
    using namespace std;
    size_t realSize = size + 2 * sizeof(int);
    void* pMem = malloc(realSize);
    if (!pMem) throw bad_alloc();
    // 将signature写入内存的最前段落和最后段落
    *(static_cast<int*>(pMem)) = signatrue;
    *(reinterpret_cast<int*>(static_cast<Byte*>(pMem)+realSize-sizeof(int))) = signature;
    // 返回指针,指向恰位于第一个signature之后的内存位置
    return static_cast<Byte*>(pMem) + sizeof(int);
}

51 编写new和delete时需固守常规

void* operator new(std::size_t size) throw(std::bad_alloc)
{
    using namespace std;
    if (size == 0) { // 处理0-byte申请
        size = 1; // 将其视为1-byte申请
    }
    while (true) {
        尝试分配size bytes;
        if (分配成功)
        return (一个指针,指向分配得来的内存);

        // 分配失败,找到当前的new-handling函数
        new_handler globalHandler = set_new_handler(0);
        set_new_handler(globalHandler);

        if (globalHandler) (*globalHandler)();
        else throw std::bad_alloc();
    }
}
class Base {
public:
    static void* operator new(std::size_t size) throw(std::bad_alloc);
    ...
};
class Derived : public Base
{ ... }; // 假设重新定义operator new
Derived* p = new Derived; // 这里调用了Base::operator new
void* Base::operator new(std::size_t size) throw(std::bad_alloc)
{
    if (size != sizeof(Base))
        return ::operator new(size);
    ...
}
void operator delete(void* rawMemory) noexcept
{
    if(rawMemory == 0) return; // 如果被删除的是个空指针就什么都不做
    归还rawMemory所指内存;
}
class Base {
public:
    static void* operator new(std::size_t size) throw(std::bad_alloc);
    static void operator delete(void* rawMemory, std::size_t size) noexcept
    ...
};

void Base::operator delete(void rawMemory, std::size_t size) noexcept
{
    if (rawMemory == 0) return;
    if (size != sizeof(Base)) {
        ::operator delete(rawMemory);
        return;
    }
    归还rawMemory所指内存;
    return;
}

52 写了placement new也要写placement delete

A* p = new A;
void* operator new(std::size_t) throw(std::bad_alloc);
void operator delete(void* rawMemory) noexcept; // global作用域中的正常签名式
void operator delete(void* rawMemory, std::size_t size) noexcept; // class作用域中典型的签名式
class A {
public:
    ...
    static void* operator new(std::size_t size, std::ostream& logStream) // 非正常形式的new
        throw(std::bad_alloc);
    static void operator delete(void* pMemory, std::size_t size) noexcept; // 正常的class专属delete
    ...
};
void* operator new(std::size_t, void* pMemory) noexcept; // placement new
A* p = new (std::cerr) A; // 调用operator new,并传递cerr作为ostream实参
// 这个动作会在构造函数抛出异常时泄露内存
void operator delete(void*, std::ostream&) noexcept;
class A {
public:
    ...
    static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
    static void operator delete(void* pMemory) noexcept;
    static void operator delete(void* pMemory, std::ostream& logStream) noexcept;
    ...
};
A* p = new (std::cerr) A; // 一如既往,但这次不再泄漏
class Base {
public:
    ...
    static void* operator new(std::size_t size, std::ostream& logStream)
        throw(std::bad_alloc); // 这个new会掩盖正常形式的new
    ...
};
Base* pb1 = new Base; // 错误,因为正常形式的operator new被掩盖
Base* pb2 = new (std::cerr) Base; // 正确,调用Base的placement new
class Derived: public Base {
public:
    ...
    static void* operator new(std::size_t size) throw(std::bad_alloc); // 重新声明正常形式的new
};
Derived* pd1 = new (std::clog) Derived; // 错误,因为Base的placement new被掩盖了
Derived* pd2 = new Derived; // 正确,调用Derived的operator new
void* operator new(std::size_t) throw(std::bad_alloc); // normal new
void* operator new(std::size_t, void*) noexcept; // placement new
void* operator new(std::size_t, const std::nothrow_t&) noexcept; // nothrow new
class StadardNewDeleteForms {
public:
    // normal new/delete
    static void* operator new(std::size_t size) throw(std::bad_alloc)
    { return ::operator new(size); }
    static void operator delete(void* pMemory) noexcept
    { ::operator delete(pMemory); }
    // placement new/delete
    static void* operator new(std::size_t size, void* ptr) noexcept
    { return ::operator new(size, ptr); }
    static void operator delete(void* pMemory, void* ptr) noexcept
    { return ::operator delete(pMemory, ptr); }
    // nothrow new/delete
    static void* operator new(std::size_t size, const std::nothrow_t& nt) noexcept
    { return ::operator new(size,nt); }
    static void operator delete(void* pMemory,const std::nothrow_t&) noexcept
    { ::operator delete(pMemory); }
};
class A : public StandardNewDeleteForms {
public:
    using StandardNewDeleteForms::operator new;
    using StandardNewDeleteForms::operator delete;

    // 添加自定义的placement new
    static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
    // 添加自定义的placement delete
    static void operator detele(void* pMemory, std::ostream& logStream) noexcept;
    ...
};
上一篇下一篇

猜你喜欢

热点阅读