类成员的内存分配

Class members memory allocation

本文关键字:分配 内存 成员      更新时间:2023-10-16

我的问题主要是理论性的。假设我们有一个类

class A{
private:
    int * a;
    int b;
private:
    A(){
      a = new int[100];
      b = 100;
    }
   ~A(){
      delete [] a;
    }
}

据我所知,如果我们动态创建A类型的对象(A * a = new A()),该对象的内存将在堆中分配,如果我使用(A a),它将在堆栈(A a)上创建。在为变量a在堆栈上创建对象的情况下,将在堆上分配对象,并且在为对象b在堆上分配对象的情况下,将在堆栈上分配对象。我要确定的第一个问题是:我是对的吗?

第二个问题是将类的所有成员存储在堆内存或堆栈内存中更有效吗?

class A{
    private:
        int * a;
        int * b;
    private:
        A(){
          a = new int[100];
          b = new int(100);
        }
       ~A(){
          delete [] a;
          delete b;
        }
    }

当我说高效时,我的意思是所有关于类成员的数据都将在堆或堆栈的内存中彼此靠近存储(实际上我不确定它们将彼此靠近存储是正确的)。

首先,c++中没有堆或堆栈。相反,我们有自动存储持续时间和动态存储持续时间。具有自动存储持续时间的对象是作用域对象。当它超出作用域时,它将被自动清除。另一方面,具有动态存储持续时间的对象不受其作用域的约束。它的生命周期只有在程序显式结束时才结束(通常这意味着调用delete)。

现在在A中,您有一个具有自动存储持续时间的对象b和一个具有动态存储持续时间的对象a。这意味着b将存在于A实例所在的任何地方。a也存在于A实例中,但它指向的内存将位于内存中的某个地方,但我们不知道在哪里。当实例被销毁时,b将自动被清理,但a将需要在析构函数中进行特殊处理,否则内存将泄漏。你可以像

    A
+------+   +----------+
|   a->+---| 100 ints |
|   b  |   +----------+
+------+

就效率而言,就像一些程序员提到的那样,你不应该真的担心这个。你应该使用你认为适合这份工作的类型。一旦你启动并运行它,你就可以分析它,找到瓶颈在哪里。如果你发现由于使用指针导致了太多的缓存丢失,那么你可以考虑尝试将数据定位到类本身。

我还想提一下,如果你发现自己写的是some_type* name = new/new[],那么你应该考虑使用std:unique_ptr<some_type>/std:unique_ptr<some_type[]>std::vector<some_type>

不,你不完全正确。

ab是对象内部的变量。它们都扩展了类的大小——至少扩展了sizeof(int*)的大小。

根据你构造对象的方式,这些变量的内存是在堆栈或堆上分配的,正如你已经提到的:

new A/int/etc在堆上分配内存

A/int/etc. var在栈上分配内存

你忽略的是你在构造函数 中分配的数据
  a = new int[100];

不是类对象的一部分。它是一些外部数据。在您的类对象中,您只有一个int*成员(大小为4-8字节,取决于体系结构)指向该数据。

首先,成员原始指针(例如MyClass)的缺点是它强制#include声明MyClass的头。这可能导致编译缓慢。为了解决这个问题,你可以使用带有向前声明的智能指针。

第二个问题是将类的所有成员存储在堆内存或堆栈内存中更有效吗?

通常最好仅在必要时使用指针。通常应该在类中将成员声明为值。它将是局部的,出错的机会更少,分配更少,最终可能出错的事情更少,编译器总是可以知道它在指定的偏移量处,所以……