Item 27 要求(或禁止)对象产生于heap之中。
(1)要求对象产生于heap之中。
class UPNumber
{
public:
UPNumber():value(0) {cout<<"UPNumber"<<endl;}
UPNumber(int initValue):value(initValue) {cout<<"UPNumber(int initValue)"<<endl;}
UPNumber(const UPNumber& rhs) {this->value=rhs.value;}
void destroy() const {delete this;}
private:
~UPNumber() { cout<<"~UPNumber"<<endl;}
int value;
};
办法:让析构函数为private,构造函数为public即可。然后导入一个伪的析构函数,来调用真正的析构函数。如上例中的destroy函数。这样的类,既能阻止派生,也能阻止作为其他类的对象成员。
如果要作为其他对象的成员可以采用如下指针成员的方式:
class Asset
{
public:
Asset(int initValue):value(new UPNumber(initValue)) {}
~Asset() {value->destroy();}
private:
UPNumber *value;
};
(2)禁止对象产生于heap上。
对象的实例化一般分为三种情况:(1)直接被实例化。(2)对象被实例化为派生类对象的基类成份。(3)内嵌于其他对象之中。
欲阻止对象直接被实例化于heap中,可以让客户无法调用new。
可以将operator new和operator delete声明为static。
class UPNumber
{
public:
UPNumber():value(0) {cout<<"UPNumber"<<endl;}
UPNumber(int initValue):value(initValue) {cout<<"UPNumber(int initValue)"<<endl;}
UPNumber(const UPNumber& rhs) {this->value=rhs.value;}
~UPNumber() { cout<<"~UPNumber"<<endl;}
private:
static void* operator new(size_t size);
static void operator delete(void* ptr);
int value;
};
如果有类从UPNumber派生,如果不再声明声明使用全局的operator new和operator delete或者声明为public,则派生类也不能在heap中产生对象。
当UPNumber作为其他类的内嵌对象,则不能阻止。
class Asset
{
public:
Asset(int initValue):value(initValue) {}
private:
UPNumber value;
};
如果Asset* p=new Asset(10);则不能阻止对象产生于heap。
我们无法判断一个地址是否位于heap,我们也无法判断一个地址是否不在heap内。
采用抽象混合式基类的技术,我们可以形成一个类,用来为派生类提供“判断某指针是否以operator new分配出来”的能力。
抽象基类:不能被实例化的基类,至少含有一个纯虚函数。
混合类:提供一组定义完好的能力,能够与派生类所提供的其他任何功能兼容。
方法如下:
class HeapTracked
{
public:
class MissingAddress {};//异常类
virtual ~HeapTracked()=0;
static void* operator new(size_t size);
static void operator delete(void* ptr);
bool isOnHeap() const;
private:
static list<const void*> addresses;
};
list<const void*> HeapTracked::addresses;
HeapTracked::~HeapTracked() {}
void* HeapTracked::operator new(size_t size)
{
void* memPtr=::operator new(size);
addresses.push_back(memPtr);
return memPtr;
}
void HeapTracked::operator delete(void* ptr)
{
list<void const*>::iterator iter=find(addresses.begin(),addresses.end(),ptr);
if(iter!=addresses.end())
{
addresses.erase(iter);
::operator delete(ptr);
}
else
{
throw MissingAddress();
}
}
bool HeapTracked::isOnHeap() const
{
const void* rawAddress=dynamic_cast<const void*>(this);
list<const void*>::iterator iter=find(addresses.begin(),addresses.end(),rawAddress);
return iter!=addresses.end();
}
class Asset:public HeapTracked
{
public:
Asset(int initValue) {}
};
调用的时候:
Asset s(10);
if(s.isOnHeap())
cout<<"is on heap"<<endl;
else
cout<<"is not on heap"<<endl;
以上则输出is not on heap
如下调用:
Asset* p=new Asset(1);
if(p->isOnHeap())
cout<<"is on heap"<<endl;
else
cout<<"is not on heap"<<endl;
delete p;
则输出is on heap。
解释其中一句代码:
const void* rawAddress=dynamic_cast<const void*>(this);
将一个指针通过dynamic_cast转换为const void* or void*这一类,就可以获得一个指针,指向“原指针所指对象的内存起始处”。