Основной вопрос об управлении памятью в C ++ - PullRequest
1 голос
/ 26 февраля 2011
// main.cpp

class Cat()
{
public:
     Cat()
     {
          a = 0;
          (*b) = 0;
     }

     int a;
     int* b;
};

int main(int argc, char* argv[])
{
     Cat cat1;
     Cat* cat2 = new Cat();
     return 0;
}

Обычно меня не волнует память, но я хочу четко понять, в какой памяти существуют cat1 и cat2 * a и b? В стеке или в куче?

@ BoPerson: Вы правы, я должен был использовать b = new int(0). Но мне более интересно, где переменная a, когда объект Cat создается в куче? a в куче тоже? И указатель b в куче тоже, и он указывает на память в куче, верно?

Ответы [ 3 ]

7 голосов
/ 26 февраля 2011

Позвольте мне аннотировать и ответить на месте.

class Cat()
{
public:
     Cat()
     {
          a = 0; // ok: sets the variable a, wherever it lives
          (*b) = 0; // not ok: stores an integer 0 to wherever b points
                    // since b was never initialized to anything, it can write
                    // anywhere you can imagine. If you are lucky, your compiler
                    // implicitly initializes the pointer to zero such that you
                    // at least get a deterministic segmentation violation.
     }

     int a; // an integer variable living wherever Cat gets constructed
     int* b; // a pointer variable living wherever Cat gets constructed pointing 
             // to wherever it gets set to (b = something) could be heap, stack, 
             // mapped memory, out-of-control (like here)
};

int main(int argc, char* argv[])
{
     Cat cat1; // allocates cat1 on the stack, all attributes (a and b) live 
               // there. Where cat1.b points to is unrestricted.
     Cat* cat2 = new Cat(); // allocates an object of class Cat on heap, 
               // allocates a pointer variable cat2 on the stack and stores the 
               // pointer to said heap-allocated Cat in it
               // again, where cat2.b points to is unrestricted.
     return 0; // maybe never reached due to segfault ;-)
}

Когда вы ссылаетесь на управление памятью в вашем заголовке: переменные стека автоматически уничтожаются, когда они выходят за пределы области видимости.Т.е. пространство, занимаемое cat1 и cat2 (один Cat, один указатель) будет восстановлено при выходе из main ().Также для cat1 будет вызван деструктор.В вашем случае явного деструктора нет, но если у Cat есть атрибуты с деструкторами, автоматический деструктор будет генерироваться автоматически.

Для указателей объект, на который указывает указатель, не уничтожается автоматически при разрушении указателя.Если вы хотите этого, вы должны взглянуть на умные указатели, такие как std :: auto_ptr <> (или QScopedPoiner в Qt), который дает вам объект, похожий на указатель, который действительно разрушит указанный объект (вызывая delete для него)когда auto_ptr разрушается.

Когда не используются умные указатели, вам нужно позаботиться о том, чтобы вручную уничтожить указатели на объекты с помощью оператора delete.Позаботьтесь о том, чтобы сделать это на каждом пути возврата из вашей текущей области (многократные возвраты, сгенерированные исключения, например).

4 голосов
/ 26 февраля 2011

Новое ключевое слово выделяет ваш объект в куче. Пока твой первый пример выделил память для стека.

Cat cat1; //stack

Cat* cat2 = new Cat(); //heap

Память стека не так легко доступна, как куча памяти. По сути, вы сохраняете память в куче с новым и сохраняете этот адрес в указателе.

Память в куче также может быть удалена. Используя команду «удалить». Что делает вашу программу более эффективной.

Мне не хватает каких-либо ключевых указателей?

РЕДАКТИРОВАТЬ: память в куче должна быть удалена, когда он больше не используется, не только для эффективности, но во избежание раздувания программы. (Утечки памяти) - Спасибо @Felice Pollano

1 голос
/ 26 февраля 2011

cat1 выделяется в стеке.Класс составляет 8 байтов (если на вашей платформе целые и указатели равны 4 байта).Первые 4 байта - это целое число a.Вторые 4 байта - это целое число b.

cat2 выделяется в памяти кучи.В остальном он точно такой же, как указано выше.

Переменные стека "ограничены".Это означает, что когда кадр стека выталкивается (то есть выходит из функции), он освобождается и вызывается его деконструктор.

Переменные кучи, с другой стороны, будут зависать до тех пор, пока вы не «удалите» память.

Также обратите внимание, что ваша конструкция искажена.«* b» разыменовывает указатель (т.е. получает данные, на которые указывает указатель).Затем вы присваиваете 0. Возникающая проблема заключается в том, что b не указывает на какую-либо определенную память, поэтому вы записываете 0 в неизвестную область памяти, которая может отсутствовать в адресном пространстве ваших процессов.Я бы подумал, что вы действительно имеете в виду "b = NULL;"

...