Существует ли максимальный предел длины массива в C++?



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



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



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



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



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

1195   11  

11 ответов:

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

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

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

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

кроме того, C++ не применяет никаких ограничений.

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

есть два места памяти могут быть выделены:

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

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

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

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

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

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

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

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

 int myArray[SIZE] 

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

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

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

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

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

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

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

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

Источники ограничений размера памяти происходят от

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

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

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

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

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

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

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

спасибо,

Роб

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

Как было отмечено во многих замечательных ответах, существует множество ограничений, которые зависят от вашей версии компилятора 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.

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

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

Я бы обошел это, сделав 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

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

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

в основном, что ваш компилятор позволит. Для Visual C++ 2017 в x64 Windows 10 box это мой максимальный предел во время компиляции перед выполнением 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 о 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;
}  

Comments

    Ничего не найдено.