定义一个只能在栈上构造对象的类

只能在堆上定义的对象可以通过声明构造函数是私有的,然后提供两个静态的方法,一个方法用来获取堆上的对象,一个用来释放堆上的对象。C++中定义一个不能被继承的类中第二种方法就是通过这种方式声明了一个不能被继承的类,但是这个类的对象就只能位于堆中了。

那么如何一定一个只能在栈上构造的对象?

这个就涉及到了C++中new这个操作符,它包含两步:

  1. 调用一个全局的operator new函数分配一定的内存空间
  2. 调用对象的构造函数

如果不允许一个类在堆上分配内存,但是允许其在栈上分配内存,对比这两种方式可以发现只需要禁止第一步的操作即可,就是禁止一个对象调用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

定义一个只能在栈上构造对象的类的相关文章

C/C++知识要点6——定义只能在堆/栈上生成对象的类

在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* ptr=new A: 区别: 静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象.使用这种方法,直接调用类的构造函数. 动态建立类对象,是使用new运算符将对象建立在堆空间中.这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配:第二步是调用构造函数构造对象,初始化这片内存空

如何定义一个只能在堆上(栈上)生成对象的类?

在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* ptr=new A:这两种方式是有区别的. 静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象.使用这种方法,直接调用类的构造函数. 动态建立类对象,是使用new运算符将对象建立在堆空间中.这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配:第二步是调用构造函数构造对象,初

设计一个只能在堆内存上实例化的类和一个只能在栈内存上实例化的类

只能在堆内存上实例化的类:将析构函数定义为private,在栈上不能自动调用析构函数,只能手动调用.也可以将构造函数定义为private,但这样需要手动写一个函数实现对象的构造. 只能在栈内存上实例化的类:将函数operator new和operator delete定义为private,这样使用new操作符创建对象时候,无法调用operator new,delete销毁对象也无法调用operator delete. #include <iostream> using namespace st

【记录一个问题】android下的ucontext协程,因为使用栈上的对象,导致cv::Mat被莫名析构

工作的流程是这样:某个协程在栈上创建task对象,在task对象内有需要返回的cv::Mat. 然后把task放到另一个线程上去执行,然后切换到别的协程,等到工作线程执行完task后,再唤醒协程. 这时候协程内去访问cv::Mat使用是empty. 同样的代码,task对象不是在栈上创建,而是new出来,一切正常. 暂未找到原因,怀疑与栈的拷贝有关.其实也打印了使用各个阶段的指针的地址,发现地址未发生改变. 原文地址:https://www.cnblogs.com/ahfuzhang/p/116

4.2-全栈Java笔记:对象和类的概念及定义

对象和类的概念 我们人认识世界,其实就是面向对象的.大家眼里都是一个个对象,要不怎么老说搞对象搞对象啊.比如现在让大家认识一下"天使"这个新事物,天使大家没见过吧,怎么样认识呢?最好的办法就是,给你们面前摆4个天使,带翅膀的美女,让大家看,看完以后,即使我不说,大家下一次是不是就都认识天使了. 但是,看完10个天使后,我们总要总结一下,什么样的东东才算天使?天使是无数的,总有没见过的!所以必须总结抽象,便于认识未知事物!总结的过程就是抽象的过程. 小时候,我们学自然数时怎么定义的?像1

C++程序设计入门(上) 之对象和类

面向对象编程: 如何定义对象?  同类型对象用一 个通用的类来定义 class C { int p; int f(); }; C ca, cb; 一个类用变量来定义数据域,用函数定义行为. class Cirle { public: double r; Cirle() { r = 1; } Cirle(double newr){ r = newr; } double get() { return r * r *3.14; } }; 构造函数: 类中有 一种特殊的“构造函数”,在创建对象时被自动调

C++中定义一个不能被继承的类

1.一种错误的解法 最开始是从构造函数开始着手(先声明这种方法不能定义一个不能被继承的类,这是一种错误的方法,但是很容易往这方面想),假设存在下面的继承体系: 现在假设B是一个不能被继承的类,那么如果存在B的子类C,那么C的构造过程应该会报错,那么如何能够让B能正常构造而C不能正常构造呢?首先A,B,C的构造函数和析构函数都假设是public的,最开始想的是让B私有继承自A,根据private继承的特性,父类中public和protected的成员在子类中都会变成private的,那么A的构造函

对象只能建立在栈上(堆上)

只能建立在栈上: //禁用new操作符,变量就只能定义在栈上了,new operator首先调用operator new,把operator new定义为private即可class A{ private: void* operator new(size_t t){} void operator delete(){} public: A(){} } 只能建立在堆上: //不能直接调用析构函数,那么就无法在栈上建立对象,在堆上建立对象是间接调用构造函数的,所以可以! //当然虽然可以在堆上建立对象

C++中如何设计一个类只能在堆或者栈上创建对象

设计一个类,该类只能在堆上创建对象 将类的构造函数私有,拷贝构造声明成私有.防止别人调用拷贝在栈上生成对象. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建 注意 在堆和栈上创建对象都会调用构造函数,为了防止在栈上创建对象我们将构造函数私有化. 拷贝构造函数是在栈上创建对象. 1 class HeapOnly 2 { 3 public: 4 static HeapOnly* CreateObject() 5 { 6 return new HeapOnly;//这使得创建该类对象都只能