Члены класса и явное распределение стека/кучи
Скажем, мы имеем 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
, который лежит в куче.