C++只在栈或堆上实例化对象

C++如何让类对象只能在堆(栈)上分配空间

一般情况下写一个类都是可以采用new在堆上分配空间,或直接采用 类名+对象名 的方式在栈上分配空间。但有时候,如果想让一个类只能在栈上或者堆上分配空间,又该怎么实现呢?

下面分别来介绍如何定义只能在栈上或堆上实例化的类。

注:
1.静态实例化对象 如 A a;的步骤为:先由编译器为对象在栈空间分配内存,移动栈顶指针,挪出适当的空间,然后在这个空间上调用构造函数形成一个对象,在对象使用完之后,调用析构函数回收内存,栈顶指针减一。
2.动态实例化对象:new操作符,第一步执行operator new()函数在堆上分配一个内存,然后调用构造函数初始化这片空间。

只能在栈上分配类对象

只有使用new运算符,对象才会建立在堆上,因此要禁用new运算符才能只在栈上分配空间。但new操作符是C++内建的,所以必须要先认清一个事实即:new operator总是先调用operator new,所以我们只要堆new操作符进行重载,并将它声明为private的,就能保证不能再使用new实例化对象,如:

class A{
private:
    void* operator new(size_t t){}
    void operator delete(void* ptr){}
public:
    A();
    ~A();
};

那么此时就不能再调用new操作符了。

只能在堆上实例化对象

容易想到的方法是将构造函数私有化,那么在类外就不能实例化对象,只能在类内提供一个共有函数使用new运算符返回一个对象,这也是典型的单例模式的由来,但在类外还是不能使用new操作符进行实例化。所以这种方法是行不通的。

所以考虑析构函数的私有化。因在栈上实例化对象之后,对象使用完毕之后自动调用析构函数,而new对象后,要手动调用delete函数才能执行对象的析构函数。
所以当析构函数被私有化之后,若在栈上实例化对象,编译器先会检查该对象的析构函数是否可用,如果不可用,则会报错。在堆上释放对象时,若不调用delete就不会发现析构函数不可访问。

这就会引发另外一个问题,使用new操作符在堆上实例化的对象要怎么析构呢?解决办法就是,在类中自定义一个公有函数用来销毁对象,该函数调用delete操作符,这样就可以使用该函数销毁对象而不是直接使用delete操作符了。
如:

class A{
public:
    A(){}
    void destroy(){delete this;}
private:
    ~A(){}

};

在此,就可以使用new在堆上创建对象而使用destroy()析构对象了。

注意:采用这种方式后,类A不能用在继承体系当中。
若A为基类,那么其析构函数就是virtual的(保证内存完全释放),子类必须要能重写该析构函数,但子类根本无法访问他,这是其一。其二,即使子类能够重写析构函数,若B是继承自A的子类,且声明了一个B类的对象b,那么此时若析构B,基类A不能被正确释放,导致内存泄露。

原文地址:https://www.cnblogs.com/lixuejian/p/12573185.html

时间: 2024-10-28 15:35:52

C++只在栈或堆上实例化对象的相关文章

C++中栈和堆上建立对象的区别

在C++中类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* p=new A(),A*p=(A*)malloc():静态建立一个类对象,是由编译器为对象在栈空间中分配内存,通过直接移动栈顶指针挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象.动态建立类对象,是使用new运算符将对象建立在堆空间中,在栈中只保留了指向该对象的指针.栈是由编译器自动分配释放 ,存放函数的参数值,局部变量的值,对象的引用地址等.其操作方式类似于数据结构中的栈,通常都是被调用时处于存储

如何限制一个类对象只在栈(堆)上分配空间?

最近做了一道题:在C++中,为了让某个类只能通过new来创建(即如果直接创建对象,编译器将报错) 其实该问题等同于如何限制一个类对象只在栈(堆)上分配空间? 一般情况下,编写一个类,是可以在栈或者堆分配空间.但有些时候,你想编写一个只能在栈或者只能在堆上面分配空间的类.这能不能实现呢?仔细想想,其实也是可以滴. 在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* ptr=new A:这两种方式是有区别的. 1.静态建立类对象:是由编译器为对象在栈空间中分配内存,

如何让类对象只在栈(堆)上分配空间?(转)

转自:http://blog.csdn.net/hxz_qlh/article/details/13135433 在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* ptr=new A:这两种方式是有区别的. 1.静态建立类对象:是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数 形成一个栈对象.使用这种方法,直接调用类的构造函数. 2.动态建立类对象,是使用new运算符将对象建立在堆空间中.这个过程分为

C++中只在栈上或者堆上申请对象

最近阅读Mitsuba的架构,有一个挺有意思的设计,开始没看明白.搜了下资料才搞懂. 有一个基类Object,它的析构函数是protected访问权限的.并且,所有继承Object的类,都需要实现一个自己的protected的析构函数. Mitsuba还特意解释了,这是为了防止在stack上构建Object的对象. 这是怎么回事呢? ”编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查.如果类的析构函数是私有的,则编译器不会在栈

栈和堆上的内存分配和回收

栈上的内存,函数结束的时候这个函数用的内存自动释放:堆上的内存,你必须自己释放,否则就会一直存在,但程序退出时,操作系统会清理进程使用的所有资源,这是就会释放掉堆,堆都没了,内存自然也没了 问题在于,很多时候进程并不会马上退出,比如服务器程序一跑就是几个月,如果分配的那块代码只跑一次那还好,但通常会反复执行,那么分配出去的内存就会越来越多,而又没有机会释放,最终的结果是堆内存耗尽,再次分配失败,程序被迫退出或者耗尽系统资源被操作系统强制杀死.

7.4.3 堆上的对象

Java的存储管理模式中,堆分配(heap-based memoryallocation,dynamic memory allocation)是Java程序员需要大致了解的.7.4.3的学习要点: 对象堆上分配的含义: 现代JVM,引用作为直接指针实现(速度和碎片整理) 1.Java对象的内存总是在heap中分配 在Java语言层面,任何Java对象所需的空间都在Java堆上动态分配,遵循堆分配的存储管理模式. 涉及两个问题: Java不在栈中保存对象的数据的好处.对比C++,程序员不需要知道对

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

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

如何限制对象只能建立在堆上或者栈上(转载)

转载:http://blog.csdn.net/szchtx/article/details/12000867 在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* ptr=new A:这两种方式是有区别的. 静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象.使用这种方法,直接调用类的构造函数. 动态建立类对象,是使用new运算符将对象建立在堆空间中.这个过程分为两步,第

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

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