2012-01-14 3 views
8

Это беспокоило меня какое-то время. Это касается моего (отсутствия) понимания разницы между распределением статической и динамической памяти. Следующий массив представляет собой обычный статический массив, который должен означать выделение памяти во время компиляции, правильно? Тем не менее, я настроил его так, чтобы пользователь вводил размер массива во время выполнения.Массив статический, но размер массива не известен до времени выполнения. Как это возможно?

#include <iostream> 
using namespace std; 

int main() { 
    cout << "how many elements should the array hold? "; 
    int arraySize; 
    cin >> arraySize; 

    int arr[arraySize]; 

    for (int i = 0; i < arraySize; ++i) 
    arr[i] = i * 2; 

    return 0; 
} 

Обратите внимание, что нет new или delete операторов в этой программе. Он отлично работает в Xcode 4.2 (компилятор Clang по умолчанию), а также в UNIX-сервере моей школы (GCC 4.4.5). Как компилятор знает, сколько памяти выделяется для arr, когда массив создается во время компиляции? Это просто случайность моего компилятора, опасный код, который может повредить другую память, или это законно?

+1

Это использует функцию под названием _variable длиной arrays_, который дебютировал в C99. –

+3

Попробуйте выполнить компиляцию с помощью 'g ++ -Wall -Wextra -pedantic -std = C++ 98' –

ответ

8

Это нестандартное расширение ваших компиляторов на C++. Обратите внимание, что в C, в отличие от C++, это официально поддерживается (т. Е. Стандартное поведение) с C99. В C++ он не поддерживается, потому что уже существует решение проблемы: используйте std::vector вместо массива.

Однако, однако, массив равен , а не, используя статическое распределение памяти (а не распределение динамической памяти), но автоматическое распределение памяти. Автоматические переменные автоматически освобождаются в конце функции (область памяти, в которой они выделены, называется стеком, потому что выделение и освобождение от нее имеют семантику стека). Чтобы массив использовал статическое распределение памяти, вам нужно было бы поставить static перед определением (обратите внимание, что переменные в глобальной области или пространстве имен всегда используют статическое распределение памяти). Однако, если вы сделаете переменную static, вы обнаружите, что компилятор больше не позволяет использовать размер непостоянного массива.

Обратите внимание, что std::vector сохраняет свои данные с помощью динамических распределений памяти. По этой причине вы также можете использовать непостоянный размер даже для статических std::vector.

+0

Основная причина, по которой это недопустимо, заключается не в том, что есть альтернатива вектора. Есть более глубокие причины, поскольку тот факт, что размер массива является частью типа, и должен быть известен во время компиляции. –

+0

@ DavidRodríguez-dribeas: они могли бы сделать исключения из этих правил, так же как и массивы переменной длины, необходимые для исключений из правил C. – celtschk

0

Это Variable Length Array (поддерживается только в C99, а не на C++). Он выделяется в стек во время выполнения.

+0

Действительно ли это C++? У IIRC Visual Studio были некоторые эротики об этом. – stativ

+0

stativ правильный; это не C++. –

+0

Нет, это не динамическое распределение памяти. Это автоматическое распределение памяти. @stativ: Нет, это неправда C++ (это было бы действительно C, если бы не было окружено кодом C++, однако). Для C++ это нестандартное расширение некоторых компиляторов. – celtschk

1

Сгенерированный код выделяет байты массива в стек во время выполнения. Как только функция возвращается, стек распаковывается, включая «отдачу» байтов, которые были выделены для него для массива.

Использование новых и удаление предназначено для выделения пространства в куче. Выделенное время жизни памяти в куче не зависит от какой-либо области функции или метода. Если вы выделяете место в ней в функции, и функция возвращается, память все еще распределяется и действительна.

4

Для массива (или любого объекта), объявленного внутри функции, память выделяется при входе в функцию (обычно в стеке) и освобождается при возврате функции. Дело в том, что функция main в этом случае не влияет на это.

Это:

cin >> arraySize; 
int arr[arraySize]; 

является "массив переменной длины" (VLA). Дело в том, что C++ не поддерживает VLA. C, начиная с стандарта ISO C 1999 года (C99), но это не особенность, принятая C++.

Ваш компилятор поддерживает VLA на C++ в качестве расширения. Использование их делает ваш код не переносным.

(Одна проблема с VLA заключается в том, что нет механизма обнаружения отказа распределения, если arraySize слишком велик, поведение программы не определено).

Для НКУ, компиляции с -pedantic будет производить предупреждение:

warning: ISO C++ forbids variable length array ‘arr’