Разница между оператором new в C++ и оператором new в java

насколько я знаю,new оператор выполняет следующие действия: (пожалуйста, поправьте меня, если я ошибаюсь.)

  1. выделяет память, а затем возвращает ссылку на первый блок выделенная память. (Очевидно, что память выделяется из кучи.)
  2. инициализировать объект (вызывающий конструктор.)

и оператор new[] работает аналогичным образом, за исключением того, что он делает это для каждого элемента в массиве.

может кто-нибудь сказать мне, как оба этих оператора и разные в C++ и Java:

  1. С точки зрения их жизненного цикла.
  2. Что делать, если они не смогут выделить память.

4 ответов


  • В C++, T * p = new T;...

    1. выделяет достаточно памяти для объекта типа T,

    2. создает объект типа T в этой памяти, возможно, его инициализации и

    3. возвращает указатель на объект. (Указатель имеет то же значение, что и адрес выделенной памяти для стандартного new, но это не обязательно должно быть для формы массива new[].)

    в случае сбоя выделения памяти, исключение типа std::bad_alloc выбрасывается, объект не создается и память не выделяется.

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

    иначе динамически выделяемой объект был построен, и пользователь должен вручную уничтожить объект и освободить память, как правило, говоря delete p;.

    фактическая функция распределения и освобождения может управляться в C++. Если нет ничего другого, глобальная, предопределенная функция , но это может быть заменить пользователем; и если существует статическая функция-членT::operator new, что будет использоваться вместо этого.

  • в Java это довольно похоже, только возвращаемое значение new - Это что-то это может привязываться к переменной Java типа T (или его основание, например Object), и у вас всегда должен быть инициализатор (так что вы скажете T x = new T();). Время жизни объекта неопределенно, но гарантированно будет по крайней мере до тех пор, пока какие-либо переменные все еще ссылаются на объект, и нет никакого способа (и никакой необходимости) уничтожить объект вручную. Java не имеет явного представления о памяти, и вы не можете контролировать interna распределения.

Кроме Того, C++ позволяет множество различных форм new выражения (так называемые размещение формы). Все они создают объекты динамического хранения, которые должны быть уничтожены вручную, но они могут быть довольно произвольными. Насколько мне известно, Java не имеет таких возможностей.


самая большая разница, наверное, в использовать: в Java, вы используете new все время за все, а вы есть to, так как это единственный способ создания объектов (типа класса). Напротив, в C++ вы почти никогда не должны иметь naked news в коде пользователя. C++ имеет неограниченные переменные, поэтому сами переменные могут быть объектами, и именно так объекты обычно используются в C++.


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

ответы на ваши вопросы:

  1. в C++ объект остается в памяти (см. Примечание), пока он не будет явно удален с delete или delete [] (и вы должны использовать тот, который соответствует тому, что вы выделено с, так a new int[1];, хотя это тот же объем памяти, как new int; не может быть удален с delete (и наоборот, delete [] не может использоваться для new int). В Java память освобождается сборщиком мусора в какой-то момент в будущем, когда "нет ссылки на память".
  2. оба бросают исключение (c++ бросает std::bad_alloc, Java что-то вроде OutOfMemoryError), но в C++ вы можете использовать new(std::nothrow) ... в этом случае new возвращает NULL, если недостаточно память, доступная для удовлетворения вызова.

примечание: согласно комментарию, технически возможно "уничтожить" объект, не освобождая его память. Это довольно необычный случай, и вы не должны этого делать, если у вас нет опыта работы с C++, и у вас есть для этого очень веская причина. Типичный вариант использования для этого находится внутри оператора delete, соответствующего размещению new (где new вызывается с уже существующим адресом памяти, чтобы просто выполнить строительство объекта (объектов)). Опять же, placement new-это в значительной степени специальное использование new, а не то, что вы можете ожидать увидеть в обычном коде C++.


у вас, кажется, есть операция new правильно, что он выделяет и инициализирует память.

после new успешно завершается, вы, программист, отвечаете за deleteing это воспоминание. Лучший способ убедиться, что это происходит, - никогда не использовать new непосредственно себя, вместо этого предпочитая стандартные контейнеры и алгоритмы и объекты на основе стека. Но если вам нужно выделить память, в C++ принято использовать смарт-указатель, как unique_ptr от В C++11 или shared_ptr из boost или C++11. Это гарантирует, что память будет восстановлена должным образом.

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


я не знаю о деталях в Java, но вот что new и new[] do в C++:

  1. выделить

    когда у вас есть выражение new T или new T(args), компилятор определяет, какую функцию вызывать для получения памяти

    • если тип T имеет соответствующий член operator new, которая называется
    • в противном случае, если пользователь предоставил соответствующие глобальные operator new что один называемый.

      если operator new не удается выделить запрошенную память, затем она вызывает новую функцию обработчика, которую вы можете установить с помощью set_new_handler. Эта функция может освободить некоторое пространство, чтобы распределение могло быть успешным, она может завершить программу или вызвать исключение типа std::bad_alloc или производные от этого. Новый обработчик по умолчанию просто бросает std::bad_alloc.

      то же самое происходит для new T[n] кроме этого operator new[] вызывается для памяти распределение.

  2. построить объект соответственно. объекты во вновь выделенной памяти.

    For new T(args) вызывается соответствующий конструктор объекта. Если конструктор создает исключение, память освобождается путем вызова соответствующего operator delete (который можно найти в тех же местах, что и operator new)

    For new T это зависит, если T является POD (т. е. встроенный тип или в основном структура/объединение C) или не. Если T-POD, ничего не происходит, иначе это рассматривается как new T().

    For new T[n] это также зависит от того,T is POD. Опять же, модули не инициализируются. Для не-стручков конструктор по умолчанию в свою очередь вызывается для каждого из объектов в порядке. Если конструктор по умолчанию одного объекта бросает, дальнейшие конструкторы не вызываются, но уже построенные объекты (которые не включают тот, чей конструктор только что бросил) разрушаются (т. е. имеют деструктор называется) в обратном порядке. Затем память освобождается с помощью соответствующего operator delete[].

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

во всех случаях объекты, пока они не будут уничтожены с delete ptr (для объектов, выделенных с помощью normal new) или delete[] ptr (для объектов, созданных с помощью array new T[n]). Если не добавлена сторонняя библиотека, в C++нет сборки мусора.

обратите внимание, что вы также можете позвонить operator new и operator delete непосредственно для выделения необработанной памяти. То же самое верно для operator new[] и operator delete[]. Однако обратите внимание, что даже для тех, кто низкоуровневый функции вы не можете смешивать вызовы, например, путем освобождения памяти с operator delete что вы выделили с operator new[].

вы также можете copnstruct объект в выделенной памяти (независимо от того, как вы это получили) с так называемым размещением new. Это делается путем указания указателя на необработанную память в качестве аргумента new, например: new(pMem) T(args). Чтобы уничтожить такой явно построенный объект, вы можете вызвать деструктор объекта напрямую,p->~T().

размещение новых работ вызывая operator new который принимает указатель в качестве дополнительного аргумента и просто возвращает его. Этот же механизм может также использоваться для предоставления другой информации operator new перегрузки, которые принимают соответствующие дополнительные аргументы. Однако пока вы можете определить соответствующий operator delete, они используются только для очистки, когда объект создает исключение во время строительства. Синтаксис "placement delete" отсутствует.

еще одно использование нового синтаксиса размещения, который уже предоставлен по C++ это nothrow новый. Этот параметр принимает дополнительный параметр std::nothrow и отличается от нормальной new только в том случае, если он возвращает нулевой указатель в случае сбоя выделения.

также обратите внимание, что new не единственный механизм управления памятью в C++. С одной стороны, существуют функции C malloc и free. Хотя обычно operator new и operator new[] просто позвони malloc, это не гарантируется. Поэтому вы не можете смешивать эти формы (например, вызывая free на указателе, указывающем в память, выделенную с помощью operator new). С другой стороны, контейнеры STL обрабатывают свои распределения через распределители, которые являются объектами, которые управляют распределением/освобождением объектов, а также строительством/уничтожением объектов в контейнерах.

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

как правило, автоматические или статические переменные предпочтительнее динамического распределения (i, e, все, что вы выделяете с new или распределители), потому что там компилятор заботится о правильном уничтожении, в отличие от динамического распределения, где вы должны сделать это самостоятельно. Если у вас есть динамически выделенные объекты, желательно, чтобы их жизнь управляется автоматическим/статические объекты (контейнеры, умные указатели) по той же причине.