【Exceptional C++(20)】内存管理(二)
2018-01-30 本文已影响13人
downdemo
问题
- 找出下列代码中与内存有关的错误
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()分配的内存