Члены класса и явное распределение стека/кучи

Скажем, мы имеем 4 класса следующим образом:

class A
{
    public:           
        A(void) : m_B()
        {
        }
    private:
        B m_B;
}

class B
{
    public:            
        B(void)
        {
           m_i = 1;
        }
    private:
        int m_i;
}

class C
{
    public:           
        C(void) 
        {
            m_D = new D();
        }
        ~C(void) 
        {
            delete m_D;
        }
    private:
        D *m_D;
}

class D
{
    public:           
        D(void)
        {
           m_i = 1;
        }
    private:
        int m_i;
}

Допустим, что существует 4 случая:

случай 1: внешнее выделение в стеке, B, внутренне выделенное в стеке

A myA1;

случай 2: внешнее выделение в куче, B внутренне выделено в стеке

A *myA2 = new A();

случай 3: C, выделенный извне в стеке, D, выделенный внутри кучи

C myC1;

случай 4: C, выделенный извне в куче, D, выделенный внутри кучи

C *myC2 = new C();

Что происходит в каждом из этих случаев? Например, в случае 2 я понимаю, что указатель myA2 выделен в стеке, объект A существует в куче, но как насчет атрибута m_B? Я предполагаю, что пространство на куче выделено для него, потому что не имеет смысла, чтобы объект существовал в кучном пространстве, а затем его атрибут выходит за пределы области видимости. Если это так, то означает ли это, что внешнее распределение кучи переопределяет распределение внутреннего стека?

Как насчет случая 3, myC1 выделяется в стеке, однако m_D выделяется в куче. Что здесь происходит? Разделяются ли две части по памяти? Если я удалил "delete m_D" из деструктора, а myC1 вышел из области видимости, будет ли утечка памяти для пространства, выделенного в куче для m_D?

Если есть какие-то учебники/статьи, которые подробно описывают это, мне бы понравилась ссылка.

Ответ 1

Я думаю, что вы путаете "распределение стека/кучи" и "автоматическая переменная".

Автоматические переменные автоматически уничтожаются при выходе из контекста.

Распределение стека заключается в том, что память выделяется в стеке выполнения. А переменной, выделенной в стеке, являются автоматические переменные.

Кроме того, - это автоматические переменные, деструкторы которых вызываются при уничтожении его владельца. В случае указателей они уничтожаются, но не основной объект, вы должны явно вызвать delete. Чтобы убедиться, что основной объект уничтожен, вы должны использовать интеллектуальные или уникальные указатели.

Другими словами: переменные/члены, которые вы должны вызвать delete on, не являются автоматическими переменными.

Наконец, член класса выделяется в том же сегменте памяти его владельца.

В вашем коде:

  • A.m_B - автоматическая переменная. Если A находится в стеке, то есть B, а A находится в куче, то есть B.
  • B.m_i и D.m_i являются автоматическими переменными и будут распределены по одному сегменту памяти их владельца.
  • Указатель C.m_D - это автоматическая переменная, но заостренный объект типа D не является, вы должны явно вызвать delete на указателе для удаления базового объекта. Таким образом, указатель C.m_D выделяется в том же сегменте памяти, но не в базовом объекте. Он очищается от новых и будет находиться в куче.

Итак:

  • Случай 1: Все находится в стеке и автоматически (т.е. уничтожается автоматически).
  • Случай 2: myA2 находится в куче, а не автоматически (вы должны delete myA2). Его член m_B2 - это автоматическая переменная, которая будет уничтожена при уничтожении myA2. Кроме того, поскольку myA2 находится в куче, m_B, как и любой член класса, находится в том же пространстве памяти, что и куча.
  • Случай 3: myC1 находится в стеке и является автоматической переменной. Указатель на m_D также находится в стеке, но не объект, на который указывает m_D, который выделяется новым в куче.
  • Случай 4: То же, что и case3, но myC2 находится в куче и не является автоматическим. Поэтому вам нужно удалить myC2 (который удалит m_D).

Ответ 2

Случай 1: все в "стеке" (автоматическое хранилище). Ресурсы освобождаются при выходе из области.

Случай 2: myA2 находится в "куче", так что это m_B, и вам остается только беспокоиться о том, чтобы освободить ресурсы, занятые myA2. он m_B будет разрушен автоматически, если myA2.

Случай 3: myC1 находится в стеке, он m_D указывает на D на кучу, но деструктор C позаботится об удалении его, так как myC1 выходит за рамки, все динамически распределенные ресурсы очищаются.

Случай 4: myC2 динамически распределяется, его необходимо удалить, чтобы освободить ресурсы, полученные им. При удалении это вызовет конструктор, который, в свою очередь, позаботится об этом m_D, как в случае 3.

Я не уверен в статьях, я уверен, что вокруг их много. Но я предлагаю прочитать некоторые хорошие книги на С++

Ответ 3

Ваш объект является частью организованной памяти. Объект не выделяет его в стек, он состоит из его членов.

Случай 2: весь объект существует в куче, это означает, что все его члены лежат в куче.

Случай 3: весь объект существует в стеке. Хитрость заключается в том, что он не является экземпляром класса D, который является членом myC1, но указатель -B физически является членом myC1. Поэтому член myC1 лежит на стеке и указывает на некоторый экземпляр D, который лежит в куче.