it-swarm.com.ru

Есть ли ограничение максимальной длины массива в C ++?

Есть ли максимальная длина для массива в C++?

Это предел C++ или это зависит от моей машины? Это настраивается? Зависит ли это от типа массива?

Могу ли я как-то нарушить этот лимит или мне нужно искать лучший способ хранения информации? И какой должен быть самый простой способ?

Что мне нужно сделать, так это хранить long long int в массиве, я работаю в среде Linux. Мой вопрос: что мне делать, если мне нужно хранить массив из N длинных целых чисел с N> 10 цифрами?

Мне это нужно, потому что я пишу некоторый криптографический алгоритм (как, например, p-Pollard) для школы и попадаю в эту стену целых чисел и длины представления массивов.

161
luiss

Есть два ограничения, оба не навязанные C++, а аппаратными.

Первый предел (никогда не должен быть достигнут) устанавливается ограничениями типа размера, используемого для описания индекса в массиве (и его размера). Он задается максимальным значением, которое может принять системный std::size_t. Этот тип данных всегда должен быть самым большим целочисленным типом системы.

Другой предел - это предел физической памяти. Чем больше ваши объекты в массиве, тем раньше будет достигнут этот предел, поскольку память заполнена. Например, vector<int> заданного размера n обычно занимает в четыре раза больше памяти, чем массив типа vector<char> (минус небольшое постоянное значение). Следовательно, vector<char> может содержать больше элементов, чем vector<int>, прежде чем заполнится память. То же самое относится к массивам собственного стиля C int[] и char[].

Кроме того, на этот верхний предел может влиять тип allocator, используемый для создания vector, поскольку allocator может свободно управлять памятью любым удобным для него способом. Очень странный, но, тем не менее, мыслимый распределитель может объединять память таким образом, чтобы идентичные экземпляры объекта совместно использовали ресурсы. Таким образом, вы можете вставить много одинаковых объектов в контейнер, который в противном случае использовал бы всю доступную память.

Кроме того, C++ не устанавливает никаких ограничений.

154
Konrad Rudolph

Никто не упомянул ограничение на размер кадр стека,.

Есть два места, где можно выделить память:

  • На куче (динамически выделяемая память).
    Ограничение размера здесь представляет собой комбинацию доступного оборудования и способности ОС имитировать пространство с помощью других устройств для временного хранения неиспользуемых данных (то есть. переместить страницы на жесткий диск).
  • В стеке (локально объявленные переменные).
    Ограничение размера здесь определяется компилятором (с возможными аппаратными ограничениями). Если вы читаете документацию компилятора, вы часто можете настроить этот размер.

Таким образом, если вы выделяете массив динамически (ограничение велико и подробно описано в других публикациях.

int* a1 = new int[SIZE];  // SIZE limited only by OS/Hardware

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

int a2[SIZE]; // SIZE limited by COMPILER to the size of the stack frame
155
Martin York

Если посмотреть на это с практической, а не теоретической точки зрения, в 32-битной системе Windows максимальный общий объем памяти, доступный для одного процесса, составляет 2 ГБ. Вы можете преодолеть ограничение, перейдя на 64-битную операционную систему с гораздо большей физической памятью, но то, делать это или искать альтернативы, во многом зависит от ваших предполагаемых пользователей и их бюджетов. Вы также можете немного расширить его, используя PAE .

Тип массива очень важен, так как выравнивание структуры по умолчанию на многих компиляторах составляет 8 байтов, что является очень расточительным, если использование памяти является проблемой. Если вы используете Visual C++ для работы с Windows, воспользуйтесь директивой # pragma pack , чтобы преодолеть это.

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

Правка: Учитывая немного больше информации о ваших точных требованиях, ваши потребности в хранилище, по-видимому, находятся между 7,6 ГБ и 76 ГБ без сжатия, что потребовало бы довольно дорогой 64-битной коробки для хранения в виде массива в памяти в C++. Возникает вопрос, почему вы хотите хранить данные в памяти, где предполагается скорость доступа, и разрешить произвольный доступ. Лучший способ хранить эти данные вне массива в значительной степени основан на том, как вы хотите получить к ним доступ. Если вам нужен случайный доступ к элементам массива, для большинства приложений существуют способы группировки групп данных, к которым обычно обращаются одновременно. Например, в больших ГИС и пространственных базах данных данные часто разбиваются по географическим областям. В терминах программирования C++ вы можете переопределить оператор массива [], чтобы при необходимости извлекать части ваших данных из внешнего хранилища.

13
SmacL

Чтобы суммировать ответы, расширить их и ответить на ваш вопрос напрямую:

Нет, C++ не накладывает никаких ограничений на размеры массива.

Но так как массив должен храниться где-то в памяти, применяются ограничения, связанные с памятью, налагаемые другими частями компьютерной системы. Обратите внимание, что эти ограничения напрямую не связаны с размеры (= количество элементов) массива, а скорее с его размер (= количество занятой памяти). Размеры (D) и размер в памяти (S) массива не совпадают, так как они связаны с памятью, занятой одним элементом ( E): S= D * E.

Сейчас E зависит от:

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

Также обратите внимание, что вы обычно получаете различные ограничения, связанные с памятью, выделяя данные массива в стеке (в виде автоматической переменной: int t[N]) или в куче (динамическое размещение с malloc()/new или используя механизмы STL), или в статической части процесса память (как статическая переменная: static int t[N]). Даже при выделении в куче вам все равно нужно небольшое количество памяти в стеке для хранения ссылок на выделенные в куче блоки памяти (но обычно это незначительно).

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

Источники ограничений объема памяти проистекают из

  • объем памяти, доступный для процесса (который ограничен 2 ^ 32 байтами для 32-битных приложений, даже в ядрах 64-битных ОС),
  • разделение памяти процесса (например, объем памяти процесса, предназначенной для стека или кучи),
  • фрагментация физической памяти (многие разбросанные небольшие фрагменты свободной памяти не применимы для хранения одной монолитной структуры),
  • количество физической памяти,
  • и объем виртуальной памяти.

Они не могут быть "подправлены" на уровне приложения, но вы можете использовать другой компилятор (для изменения пределов размера стека), или перенести ваше приложение на 64-битную версию, или перенести его на другую ОС, или изменить физический/конфигурация виртуальной памяти (виртуальной? физической?) машины.

Нередко (и даже желательно) рассматривать все вышеперечисленные факторы как внешние помехи и, следовательно, как возможные источники ошибок времени выполнения, а также тщательно проверять и реагировать на ошибки, связанные с выделением памяти в программном коде.

И наконец: хотя C++ не накладывает никаких ограничений, вам все равно придется проверять наличие неблагоприятных условий, связанных с памятью, при запуске вашего кода ...: -)

4
Artur Opalinski

Я бы согласился с вышесказанным, что если вы начинаете свой массив с

 int myArray[SIZE] 

тогда размер ограничен размером целого числа. Но вы всегда можете malloc кусок памяти и иметь указатель на него, настолько большой, насколько вы хотите, если malloc не возвращает NULL.

4
Tarski

Как отмечалось много отличных ответов, существует множество ограничений, которые зависят от вашей версии компилятора C++, операционной системы и характеристик компьютера. Тем не менее, я предлагаю следующий скрипт для Python, который проверяет ограничение на вашем компьютере.

Он использует бинарный поиск и на каждой итерации проверяет, возможен ли средний размер, создавая код, который пытается создать массив такого размера. Сценарий пытается скомпилировать его (извините, эта часть работает только в Linux) и настроить бинарный поиск в зависимости от успеха. Проверьте это:

import os

cpp_source = 'int a[{}]; int main() {{ return 0; }}'

def check_if_array_size_compiles(size):
        #  Write to file 1.cpp
        f = open(name='1.cpp', mode='w')
        f.write(cpp_source.format(m))
        f.close()
        #  Attempt to compile
        os.system('g++ 1.cpp 2> errors')
        #  Read the errors files
        errors = open('errors', 'r').read()
        #  Return if there is no errors
        return len(errors) == 0

#  Make a binary search. Try to create array with size m and
#  adjust the r and l border depending on wheather we succeeded
#  or not
l = 0
r = 10 ** 50
while r - l > 1:
        m = (r + l) // 2
        if check_if_array_size_compiles(m):
                l = m
        else:
                r = m

answer = l + check_if_array_size_compiles(r)
print '{} is the maximum avaliable length'.format(answer)

Вы можете сохранить его на своем компьютере и запустить, и он напечатает максимальный размер, который вы можете создать. Для моей машины это 2305843009213693951.

3
Dmitry Torba

Одна вещь, которую я не думаю, была упомянута в предыдущих ответах.

Я всегда ощущаю "неприятный запах" в смысле рефакторинга, когда люди используют такие вещи в своем дизайне.

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

веселит,

Обкрадывать

2
Rob Wells

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

2
Jay

Как ни досадно неспецифично, как все текущие ответы, они в основном правильные, но со многими оговорками, не всегда упоминаемыми. Суть в том, что у вас есть два верхних предела, и только один из них действительно определен, так что YMMV :

1. Ограничение времени компиляции

В основном то, что позволит ваш компилятор. Для Visual C++ 2017 в 64-разрядной версии Windows 10 это мой максимальный лимит во время компиляции до ограничения в 2 ГБ,

unsigned __int64 max_ints[255999996]{0};

Если бы я сделал это вместо этого,

unsigned __int64 max_ints[255999997]{0};

Я бы получил:

Error C1126 automatic allocation exceeds 2G

Я не уверен, как 2G коррелирует с 255999996/7. Я гуглил оба числа, и единственное, что я мог найти, что, возможно, было связано, было это * nix Q & A о проблема точности с dc . В любом случае, кажется, что не имеет значения, какой тип массива int вы пытаетесь заполнить, сколько элементов может быть выделено.

2. Ограничения времени выполнения

Ваш стек и куча имеют свои ограничения. Эти ограничения являются значениями, которые изменяются в зависимости от доступных системных ресурсов, а также от того, насколько "тяжелым" является само ваше приложение. Например, с моими текущими системными ресурсами я могу заставить это работать:

int main()
{
    int max_ints[257400]{ 0 };
    return 0;
}

Но если я немного подправлю ...

int main()
{
    int max_ints[257500]{ 0 };
    return 0;
}

Бам! Переполнение стека!

Exception thrown at 0x00007FF7DC6B1B38 in memchk.exe: 0xC00000FD:Stack overflow (parameters: 0x0000000000000001, 0x000000AA8DE03000).Unhandled exception at 0x00007FF7DC6B1B38 in memchk.exe: 0xC00000FD:Stack overflow (parameters: 0x0000000000000001, 0x000000AA8DE03000).

И просто, чтобы детализировать всю тяжесть вашего приложения, это было хорошо, чтобы пойти:

int main()
{
    int maxish_ints[257000]{ 0 };
    int more_ints[400]{ 0 };
    return 0;
}  

Но это вызвало переполнение стека:

int main()
{
    int maxish_ints[257000]{ 0 };
    int more_ints[500]{ 0 };
    return 0;
}  
1
kayleeFrye_onDeck

я бы обойти это, создав 2d динамический массив:

long long** a = new long long*[x];
for (unsigned i = 0; i < x; i++) a[i] = new long long[y];

подробнее об этом здесь https://stackoverflow.com/a/936702/3517001

0
Three

Как уже указывалось, размер массива ограничен вашим оборудованием и вашей ОС (man ulimit). Ваше программное обеспечение может быть ограничено только вашим творческим потенциалом. Например, вы можете хранить свой "массив" на диске? Вам действительно нужны длинные длинные целые? Вам действительно нужен плотный массив? Вам вообще нужен массив?

Одним из простых решений было бы использовать 64-битный Linux. Даже если у вас недостаточно физического ОЗУ для массива, ОС позволит вам распределять память так, как если бы вы это делали, поскольку виртуальная память, доступная вашему процессу, вероятно, намного больше, чем физическая память. Если вам действительно нужен доступ ко всему в массиве, это равносильно хранению его на диске. В зависимости от ваших шаблонов доступа, могут быть более эффективные способы сделать это (например, используя mmap () или просто последовательно хранить данные в файле (в этом случае 32-битного Linux будет достаточно)).

0
ejgottl