C++:设计一个类,只在堆上 / 栈上创建对象

本文探讨如何设计C++类,确保对象只在堆或栈上创建。通过私有化构造函数并提供静态接口,限制堆或栈上的对象创建。在C++98和C++11中,采用不同的方法封杀拷贝构造函数和阻止堆分配,但全局对象仍可能创建。

设计一个类,只在堆上创建对象

class HeapOnly
{
public:
	static HeapOnly* GetHeapObj()
	{
		return new HeapOnly;
	}
private:
	//构造函数私有
	HeapOnly()
	{}
	//C++98:拷贝构造函数只声明不实现,并且声明成私有的
	HeapOnly(const HeapOnly&);
	//C++11:拷贝构造函数delete
	HeapOnly(const HeapOnly&) = delete;
};
int main()
{
	HeapOnly* obj = HeapOnly::GetHeapObj();//产生堆上的对象
}

思路分析:

  1. 构造函数要定义为私有的,因为调用构造函数产生的对象都在栈上
  2. 但是构造函数私有之后,对象new不出来了,因此要在类里面提供接口GetHeapObj,然后直接返回new出来的对象,这样产生的对象就在堆上
  3. 但是要调用这个GetHeapObj接口的话只有通过对象才能调用,而我们不能调用构造产生对象,那么应该怎么办呢?那就是把这个接口定义为静态的,静态的成员函数不需要对象也可以调用。
  4. 那又出现一个问题,如果我们调用这个GetHeapObj接口然后成功的产生了一个堆上的对象,如果再调用拷贝构造函数又会产生栈上的对象。所以我们要把拷贝构造函数也封杀掉,那如果是在C++98中我们就把拷贝构造函数只声明不实现就可以了,如果是在C++11中我们可以使用delete将这个函数删除,像这样HeapOnly(const HeapOnly&) = delete;也是可以的。
  5. 把构造函数封杀了,因此全局的变量也不可以被定义,所以就只能在堆上创建对象了

设计一个类,只在栈上创建对象

方法一:
class StackOnly
{
public:
	static StackOnly GetStackObj()
	{
		return StackOnly();
	}
private:
	StackOnly()
	{}
};
int main()
{
	StackOnly obj = StackOnly::GetStackObj();
}

思路分析:

  1. 构造函数要定义成私有的,因为防止new创建出堆上的对象
  2. 在类里提供GetStackObj接口,直接返回栈上的对象
  3. 同时把GetStackObj接口设置为静态的,不用对象也可以调用
  4. 因为这样把构造函数封杀了,因此全局的变量也不可以被定义,所以就只能在栈上创建对象了
方法二(C++98)
class StackOnly
{
public:
	static StackOnly GetStackObj()
	{
		return StackOnly();
	}
private:
	void* operator new(size_t size);
	void operator delete(void* p);
};
int main()
{
	StackOnly obj = StackOnly::GetStackObj();
}

思路分析:
这里是针对C++98,可以把operator new和operator delete放在私有里,这样就不能创建出堆上的对象了,但是这里会有一个bug就是全局的对象可以被创建出来。

方法三(C++11)
class StackOnly
{
public:
	static StackOnly GetStackObj()
	{
		return StackOnly();
	}
	void* operator new(size_t size) = delete;
	void operator delete(void* p) = delete;
};
int main()
{
	StackOnly obj = StackOnly::GetStackObj();
}

思路分析:
这里是针对C++11,可以直接把operator new和operator delete用delete删除,这样就不会创建出堆上的对象,但是这里和方法二一样有一个bug就是全局的对象可以被创建出来。

### C++上和堆上创建对象的方法 在C++中,对象可以创建在上或堆上。两者的创建方式和管理机制存在显著差异。 #### 创建对象 上的对象是通过直接定义变量的方式创建的,这种方式称为自动存储(automatic storage)。当对象超出作用域时,系统会自动销毁该对象并释放其占用的内存[^1]。例如: ```cpp Object obj; // 在创建对象 ``` 上述代码会在上创建一个名为`obj`的对象。上的对象生命周期与其所在的作用域相关联,一旦离开作用域,对象会被自动销毁[^4]。 #### 堆上创建对象 堆上的对象需要使用`new`关键字进行动态分配。这种分配方式称为动态存储(dynamic storage),程序员需要手动管理堆内存的分配与释放。例如: ```cpp Object* pObj = new Object(); // 在堆上创建对象 delete pObj; // 手动释放堆上的对象 ``` 上述代码首先通过`new`在堆上创建了一个`Object`对象,并返回指向该对象的指针`pObj`。由于堆上的对象不会自动销毁,因此必须显式调用`delete`来释放内存,以避免内存泄漏[^3]。 #### 与堆的区别 - 上的对象由编译器自动管理,无需手动释放内存。 - 堆上的对象需要程序员手动管理,使用`new`分配,使用`delete`释放。 - 内存空间有限,适合存储小型对象;堆内存空间较大,适合存储大型对象或需要长期存在的对象。 ### 示例代码 以下是一个完整的示例,展示了如何在堆上创建对象: ```cpp #include <iostream> using namespace std; class Object { public: Object() { cout << "Constructor called" << endl; } ~Object() { cout << "Destructor called" << endl; } }; int main() { // 创建对象 Object objStack; // 自动存储,构造函数被调用 // 堆上创建对象 Object* pObjHeap = new Object(); // 动态存储,构造函数被调用 // 手动释放堆上的对象 delete pObjHeap; // 析构函数被调用 return 0; } ``` 运行结果: ``` Constructor called Constructor called Destructor called Destructor called ``` 从输出可以看出,上的对象在离开作用域时自动调用析构函数,而堆上的对象需要显式调用`delete`后才会调用析构函数[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值