C++——禁止对象产生在heap

有些类的对象我们并不希望在堆区开辟。举一个例子。我们有一个文件关闭器,就是一个RAII类,负责文件的正常关闭。

template <typename FStream>
struct FileCloser
{
    FStream & _file_stream;
    FileCloser(FStream & file_stream) : _file_stream(file_stream)
    { }

    ~FileCloser()
    {
        _file_stream.close();
    }
};

很简单也很容易实现,不是吗?领这个类的对象开辟在堆区我想应当是毫无意义的。

从性能的角度来讲,我们的成员只有一个引用而已,就是经过包装后的指针。在栈区开辟耗费不了多大的栈区内存。相反,如果使用new来产生一个对象,那么会先调用operator new然后再调用定位new来构造对象。相对于在栈区创建对象的事件,在堆区创建应当慢许多。

从资源泄露的角度来讲。我们定义了一个RAII的时候,就是为了避免资源泄露。如果读者有过使用智能指针的经验。你会发现,你似乎从没在heap中创建一个智能指针——好嘛,本来是为了管理资源泄露,这回RAII对象也有可能资源泄漏(不被delete)。

所以,对于某些特殊的对象,不让其产生在heap上是有一定道理的。

具体的做法

static void * operator new(size_t) = delete;
static void operator delete (void *) = delete;

在C++11中,你只需要在类中加上这两行代码即可。这表示这个类的new是被删除的,也就是说不能再heap中创建对象。十分的简单。如果使用的事C++11以下的版本,只需要将其声明为private即可——不过这样也是有一定的隐患,你要确保类中没有友元函数或者类中的成员函数不会调用它。

你也可以如法炮制的这样

  static void * operator new[](size_t) = delete;
  static void operator delete[](void * p)= delete;

就是数组的形式。

你也可以仅仅声明new的运算符是被删除的。但是这样做是一个不合理的行为。声明了new是被删除的。为什么不声明delete是被删除的?

如此这样你就可以避免任何形式的在堆区开辟对象。

或许你会说,我可以使用malloc开辟空间,使用定位new来进行构造对象。

我们且不说这样有多麻烦,一般这种工作都是由new operator(注意和operator new的区别)来完成。或者是由分配器来完成。而且这样麻烦你确定不会在中出错?好在在new声明为被删除的情况下对应的定位new也会编译错误。就像这样。Foo的new被声明为删除的。

    auto p = static_cast<Foo*>(::operator new(sizeof (Foo)));
    new (p) Foo;

我们会得到这样的一个编译错误。

No matching function for call to 'operator new'

希望篇博客可以帮助你,以上就是禁止对象在堆区开辟对象的这个手法的大概内容。 

make_heap、push_heap、pop_heap和sort_heap都是C++ STL库中的算法,用于操作堆(heap)数据结构。 1. make_heap:将一个无序的区间转换为堆。函数原型如下: ``` template <class RandomAccessIterator> void make_heap (RandomAccessIterator first, RandomAccessIterator last); ``` 其中,first和last分别为区间的起始和结束迭代器。make_heap函数会将[first,last)区间转换为堆。调用该函数后,该区间的最大元素会被放在第一个位置上。 2. push_heap:将一个元素添加到堆中。函数原型如下: ``` template <class RandomAccessIterator> void push_heap (RandomAccessIterator first, RandomAccessIterator last); ``` 其中,first和last分别为区间的起始和结束迭代器。当前,[first,last-1)已经是一个堆,push_heap函数将last-1位置的元素添加到堆中,并且保证该堆仍然是一个堆。 3. pop_heap:将堆的最大元素移动到末尾。函数原型如下: ``` template <class RandomAccessIterator> void pop_heap (RandomAccessIterator first, RandomAccessIterator last); ``` 其中,first和last分别为区间的起始和结束迭代器。当前,[first,last)已经是一个堆,pop_heap函数将该堆的最大元素(即first位置的元素)移动到last-1位置,并且保证[first,last-1)仍然是一个堆。 4. sort_heap:将一个堆排序。函数原型如下: ``` template <class RandomAccessIterator> void sort_heap (RandomAccessIterator first, RandomAccessIterator last); ``` 其中,first和last分别为区间的起始和结束迭代器。当前,[first,last)已经是一个堆,sort_heap函数会将该堆转换为有序序列。 需要注意的是,这几个函数都要求操作的区间是一个随机访问迭代器(RandomAccessIterator)类型的迭代器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值