只能在堆上定义的对象可以通过声明构造函数是私有的,然后提供两个静态的方法,一个方法用来获取堆上的对象,一个用来释放堆上的对象。C++中定义一个不能被继承的类中第二种方法就是通过这种方式声明了一个不能被继承的类,但是这个类的对象就只能位于堆中了。
那么如何一定一个只能在栈上构造的对象?
这个就涉及到了C++中new这个操作符,它包含两步:
- 调用一个全局的operator new函数分配一定的内存空间
- 调用对象的构造函数
如果不允许一个类在堆上分配内存,但是允许其在栈上分配内存,对比这两种方式可以发现只需要禁止第一步的操作即可,就是禁止一个对象调用operator new函数。这可能就涉及到了operator new这个库函数了,对于类,这个库函数是可以被重载的,只需要将它重载成私有的即可。这是C++ reference中对operator
new的说明。可以查看这个链接中对operator new的说明即可。下面的函数原型就是从上面的文档中拷贝过来的。这里甚至可以不写实现。
#include <iostream> #include <new> using namespace std; class A { public: A() { cout<<"a con"<<endl; } ~A() { cout<<"a des"<<endl; } private: static void* operator new (std::size_t size) throw (std::bad_alloc); static void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw(); static void* operator new (std::size_t size, void* ptr) throw(); }; int main() { A a; A * ap=new A(); return 0; }
可以发现输出提示错误:
如果把main函数中第二行代码去掉,函数是可以正常运行的:
即表示它可以在栈上构造对象。
同时在看上面new的过程中发现了new其实可以使用栈上的内存来构造对象。就是使用placement new这个版本,如果提供给new一个栈上的地址,它会在栈上构造对象。注意使用placement new这个版本时需要显示调用析构函数。
#include <iostream> using namespace std; class A { public: A(int t=1) { d=t; cout<<d<<"a con"<<endl; } int d; ~A() { cout<<d<<"a des"<<endl; } }; int main() { const int Len=sizeof(A); char buf[Len]; A * a=new(buf) A(2);//调用placement new这个版本 a->~A();//注意这里需要显示调用析构函数,因为buf中的内存是在栈中的,所以函数跳出后内存会被释放 return 0; }
执行输出:
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-09-29 05:36:35