美文网首页Exceptional C++
【Exceptional C++(20)】内存管理(二)

【Exceptional C++(20)】内存管理(二)

作者: downdemo | 来源:发表于2018-01-30 13:02 被阅读13次

    问题

    • 找出下列代码中与内存有关的错误
    class B {
    public:
        virtual ~B();
        void operator delete(void*, size_t) throw();
        void operator delete[](void*, size_t) throw();
        void f(void*, size_t) throw();
    };
    class D : public B {
    public:
        void operator delete(void*) throw();
        void operator delete[](void*) throw();
    };
    void f()
    {
        // 下列语句中调用的是哪个delete
        // 调用时的参数是什么
        D* pd1 = new D;
        delete pd1;
        B* pb1 = new D;
        delete pb1;
        D* pd2 = new D[10];
        delete[] pd2;
        B* pb2 = new D[10];
        delete[] pb2;
        // 下面两个赋值语句合法吗?
        B b;
        typedef void (B::*PMF)(void*, size_t);
        PMF p1 = &B::f;
        PMF p2 = &B::operator delete;
    }
    class X {
    public:
        void* operator new(size_t s, int)
        throw(bad_alloc) {
            return ::operator new(s);
        }
    };
    class SharedMemory {
    public:
        static void* Allocate(size_t s) {
            return OsSpecificSharedMemAllocation(s);
        }
        static void Deallocatate(void* p, int i) {
            OsSpecificSharedMemDeallocation(p, i);
        }
    };
    class Y {
    public:
        void* operator new(size_t s, SharedMemory& m)
        throw(bad_alloc) {
            return m.Allocate(s);
        }
        void operator delete(void* p, SharedMemory& m, int i)
        throw() {
            m.Deallocate(p, i);
        }
    };
    void operator delete(void* p) throw() {
        SharedMemory::Deallocate(p);
    }
    void operator delete(void* p, std::nothrow_t&) throw() {
        SharedMemory::Deallocate(p);
    }
    

    解答

    • B的delete有第二个参数而D没有,这是出于个人喜好,两种写法都可行
    • 两个类都提供了delete和delete[]却没有提供new和new[]
    • 调用的delete版本
        D* pd1 = new D;
        delete pd1; // D::operator delete(void*)
        B* pb1 = new D;
        delete pb1; // D::operator delete(void*)
        D* pd2 = new D[10];
        delete[] pd2; // D::operator delete[](void*)
        B* pb2 = new D[10];
        delete[] pb2; // 不可预料的行为
        // 传递给delete的指针静态类型必须与动态类型一样
    
    • 再看看下面赋值语句的问题
        B b;
        typedef void (B::*PMF)(void*, size_t);
        PMF p1 = &B::f;
        PMF p2 = &B::operator delete;
    
    • 第二个赋值语句不合法,void operator delete(void*, size_t) throw()不是B的成员函数,虽然看起来很像,new和delete总是静态的,即使不显式声明为static,总是把它们声明为static是个好习惯
    class X {
    public:
        void* operator new(size_t s, int)
        throw(bad_alloc) {
            return ::operator new(s);
        }
    };
    
    • 这会产生内存泄漏,因为没有相应的placement delete
    class SharedMemory {
    public:
        static void* Allocate(size_t s) {
            return OsSpecificSharedMemAllocation(s);
        }
        static void Deallocatate(void* p, int i) {
            OsSpecificSharedMemDeallocation(p, i);
        }
    };
    class Y {
    public:
        void* operator new(size_t s, SharedMemory& m)
        throw(bad_alloc) {
            return m.Allocate(s);
        }
    
    • 同理,这里没有对应的delete,如果用这个函数分配的内存放置对象的构造过程中抛出异常,内存就不会被正常释放,例如
    SharedMemory shared;
    ...
    new (shared) T; // if T::T() throws, memory is leaked
    
    • 这里内存还无法被安全删除,因为类中没有正常的operator delete
        void operator delete(void* p, SharedMemory& m, int i)
        throw() {
            m.Deallocate(p, i);
        }
    };
    

    这个delete完全没用,因为它从不会被调用

    void operator delete(void* p) throw() {
        SharedMemory::Deallocate(p);
    }
    
    • 这是一个严重错误,因为它将要删除那些被缺省的::operator new分配出来的内存而非SharedMemory::Allocate()分配的
    void operator delete(void* p, std::nothrow_t&) throw() {
        SharedMemory::Deallocate(p);
    }
    
    • 同理,这里的delete只会在new(nothrow)T失败时才被调用,因为T的构造函数会带着一个异常来终止,并企图回收那些不是SharedMemory::Allocate()分配的内存

    相关文章

      网友评论

        本文标题:【Exceptional C++(20)】内存管理(二)

        本文链接:https://www.haomeiwen.com/subject/wttczxtx.html