2015-11-03 4 views
0

Рассмотрим следующий фрагмент кода:C++: Статические указатели, статические объекты и динамическая память распределения

#include <iostream> 
using namespace std; 

class p 
{ 
    public: 
    int* q; 
    p() 
    { 
     q = new int(100); 
    } 
    ~p(){ 
     delete q; 
    } 
}; 

static p* p1 = new p(); 
static p p2; 

int main() { 
    // your code goes here 
    std::cout << *(p1->q); 
    std::cout << *(p2.q); 

    delete p1; 
} 

p1 и p2 являются статическими вары, они должны храниться в статическом сегменте.

  1. поскольку p1 является указателем, является только адресом указателя, сохраненным в статическом сегменте или даже объектом, на который он указывает?

  2. p2 - обычный статический объект, но он содержит динамически распределенную переменную-член q, поэтому q также сохраняется в статическом сегменте?

+0

Нет, и нет. Что еще более важно, вам все равно. –

+0

Почему вы не запускаете код и не видите сами? – CrakC

+0

@CrakC это, как правило, не очень хорошая идея с C++. – Quentin

ответ

3
  1. p1 является указателем, он хранится в статическом сегменте (я не уверен, что это правильный термин), объект или памяти p1 точек на на куче.

  2. p2 - объект, он хранится в статическом сегменте. q - указатель внутри p2, объект или память q указывает на то, что на куче.

0

У вас есть два объекта, которые статически, указатель с именем p1 и экземпляр типа p имени p2.

В вашей программе есть два места, где могут возникать динамические распределения: в конструкторе класса p и при инициализации статической переменной p1.

Статически выделенные объекты p1 (указатель) и p2 (экземпляр класса) существуют до тех пор, пока программа запускается. Важно выделить указатель p1, содержащий только адрес из экземпляра класса по этому адресу. (Этот экземпляр будет создан во время выполнения на new p()). Указатель и «указатель» могут иметь независимые времена жизни; оба существуют независимо друг от друга. Указатель может существовать и не указывать на что-либо, и объект, созданный вызовом new p(), может существовать дольше, чем любой указатель на него.

Ниже представлена ​​последовательность событий, которая разворачивается при стартовой программе. Инициализация статических переменных указана в разделе 3.6.2 стандарта C++ 11.

  1. Распределение переменных с статической продолжительностью хранения, здесь p1 и p2. Рабочая модель заключается в том, что память является частью программы.

  2. Обнуление этих переменных. «Переменные со статической продолжительностью хранения [...] должны быть инициализированы нулем перед любой другой инициализацией». Указатель p1, а также память, в которой теперь находится p2, состоят из байтов, которые все равны нулю.

  3. Dynamic (т.е. времени выполнения) инициализации этих переменных в порядке их определения:

    • Инициализация указателя p1 начинается с вызова new p().
      • Память для нового объекта типа p распределяется динамически («на куче») со стандартным распределителем. Содержимое памяти не инициализировано и неизвестно. Объект не имеет имени, поэтому назовем его x.
      • x 'конструктор выполнен с целью его инициализации.
        • Конструктор присваивает значение до сих пор неинициализированной переменной-члену x.q. x.q является частью x и как таковой находится в памяти, динамически распределенной ранее.
        • Правая сторона задания - это еще один вызов new, на этот раз для int. Стандартный распределитель динамически выделяет память для int, которая инициализируется с помощью 100.
        • Возвращаемое значение new является адресом памяти, в котором находится int, который присваивается указателю int x.q.
      • x 'конструктор возвращает, и new p() возвращает адрес памяти, где x проживает.
      • Это возвращаемое значение присваивается до сих пор нулевым инициализированным p1, которое теперь указывает на неназванный экземпляр p, который мы назвали x.
    • Инициализация p2. Выполняется конструкторp2, который выполняет то же самое, что и конструктор x: Он вызывает new для int, который вызывает распределение динамической памяти, инициализирует его значением 100 и присваивает адрес ячейки памяти int p2.q.

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

Memory schematics of your program

Это должно помочь ответить на ваши вопросы:

  1. p1 находится в «статическом сегменте», если вы хотите, но объект он указывает было динамически выделяемой во время выполнения позвоните по телефону new.
  2. Статический объект p2не содержит «динамически распределенная переменная элемента q». Это предложение смущает переменную-член - указатель с именем q - с объектом , которому q баллов,, который является динамически выделяемым int.Переменная-член q хранится везде, где хранится содержащийся экземпляр класса p; Фактически, это является единственными данными в этом случае. (Попробуйте sizeof(p)!) Объект, к которому относится элемент любого экземпляра q, - это всегда динамически выделяемый int (ну, пока какой-то злонамеренный программист не присвоит вашему публике другое значение q).


Это будет представлять собой утечку памяти, поскольку динамически выделенный объект, адрес которого был утрачен никогда не могут быть удалены программой.

Смежные вопросы