What does *new int mean?
The memory allocated on line (*) below is not deleted.
Without changing the code on line (*), is there any way to avoid leaking memory? If so, how? If not, why not?
What I don’t understand is, what does *new int mean? Specifically, what does adding the * beside new mean?
Also, what if instead of int z, we have int &z ?
4 Answers 4
That line is the memory leak. It also makes no sense what so ever allocating an int int on heap and derefencing it (with * ) before saving it’s handle (address returned by new ). So the only posible way to avoid the leak is:
Without changing the code on line (*), is there any way to avoid leaking memory?
In real life, you would absolutely change that line — it’s insane.
Assuming this is an intellectual exercise, then possibilities are:
- Add return; before it, so the new never happens;
- Override ::operator new to return a pointer that you can access by other means, such as a global variable.
What I don’t understand is, what does *new int mean?
new int dynamically allocates an object of type int , and gives a pointer to that. * dereferences that pointer so that the object can be copied to initialise z . The pointer is not stored anywhere, so there is no way to access or delete the dynamic object afterwards.
Also, the initialisation of z from the value of an uninitialised object gives undefined behaviour.
Also, what if instead of int z , we have int &z ?
z would be a reference to, rather than a copy of, the dynamic object. It would then be possible to fix the leak with delete &z . That would be an unidiomatic, confusing thing to do; don’t do it in real code.
In general, avoid dynamic allocation and, when it is necessary, manage dynamic resources with RAII types, like containers and smart pointers. Raw pointers are error-prone, expecially when exceptions are thrown; anything else is a recipe for insanity.
new expression
Creates and initializes objects with dynamic storage duration, that is, objects whose lifetime is not necessarily limited by the scope in which they were created.
Contents
[edit] Syntax
| :: (optional) new ( type ) initializer (optional) | (1) |
| :: (optional) new new-type initializer (optional) | (2) |
| :: (optional) new ( placement-params ) ( type ) initializer (optional) | (3) |
| :: (optional) new ( placement-params ) new-type initializer (optional) | (4) |
The initializer is not optional if
- type or new-type is an array of unknown bound
- a placeholder is used in type or new-type , that is, auto or decltype ( auto ) (since C++14) , possibly combined with a type constraint (since C++20)
- a class template is used in type or new-type whose arguments need to be deduced
[edit] Explanation
The new expression attempts to allocate storage and then attempts to construct and initialize either a single unnamed object, or an unnamed array of objects in the allocated storage. The new-expression returns a prvalue pointer to the constructed object or, if an array of objects was constructed, a pointer to the initial element of the array.
If type is an array type, all dimensions other than the first must be specified as positive integral constant expression (until C++14) converted constant expression of type std::size_t (since C++14) , but (only when using un-parenthesized syntaxes (2) and (4) ) the first dimension may be an expression of integral type, enumeration type, or class type with a single non-explicit conversion function to integral or enumeration type (until C++14) any expression convertible to std::size_t (since C++14) . This is the only way to directly create an array with size defined at runtime, such arrays are often referred to as dynamic arrays:
The behavior is undefined if the value in the first dimension (converted to integral or enumeration type if needed) is negative.
In the following cases the expression specifying the first dimension is erroneous:
- the expression is of non-class type and its value before conversion to std::size_t is negative;
- the expression is of class type and its value after user-defined conversion function and before the second standard conversion is negative;
- the value of the expression is larger than some implementation-defined limit;
- the value is smaller than the number of array elements provided in the brace-enclosed initializer (including the terminating ‘\0’ on a string literal).
If the value in the first dimension is erroneous for any of these reasons,
- if, after conversion to std::size_t , the first dimension is a core constant expression and it is potentially evaluated, the program is ill-formed,
- otherwise, if the allocation function that would have been called is non-throwing, the new-expression returns the null pointer of the required result type,
- otherwise, the new-expression does not call the allocation function, and instead throws an exception of a type that would match an exception handler of type std::bad_array_new_length .
The first dimension of zero is acceptable, and the allocation function is called.
Note: std::vector offers similar functionality for one-dimensional dynamic arrays.
[edit] Allocation
The new-expression allocates storage by calling the appropriate allocation function. If type is a non-array type, the name of the function is operator new . If type is an array type, the name of the function is operator new[] .
As described in allocation function, the C++ program may provide global and class-specific replacements for these functions. If the new-expression begins with the optional :: operator, as in :: new T or :: new T [ n ] , class-specific replacements will be ignored (the function is looked up in global scope). Otherwise, if T is a class type, lookup begins in the class scope of T .
When calling the allocation function, the new-expression passes the number of bytes requested as the first argument, of type std:: size_t , which is exactly sizeof ( T ) for non-array T .
Array allocation may supply unspecified overhead, which may vary from one call to new to the next, unless the allocation function selected is the standard non-allocating form. The pointer returned by the new-expression will be offset by that value from the pointer returned by the allocation function. Many implementations use the array overhead to store the number of objects in the array which is used by the delete [ ] expression to call the correct number of destructors. In addition, if the new-expression is used to allocate an array of char , unsigned char , or std::byte (since C++17) , it may request additional memory from the allocation function if necessary to guarantee correct alignment of objects of all types no larger than the requested array size, if one is later placed into the allocated array.
New-expressions are allowed to elide or combine allocations made through replaceable allocation functions. In case of elision, the storage may be provided by the compiler without making the call to an allocation function (this also permits optimizing out unused new-expression). In case of combining, the allocation made by a new-expression E1 may be extended to provide additional storage for another new-expression E2 if all of the following is true:
Note that this optimization is only permitted when new-expressions are used, not any other methods to call a replaceable allocation function: delete [ ] new int [ 10 ] ; can be optimized out, but operator delete ( operator new ( 10 ) ) ; cannot.
During an evaluation of a constant expression, a call to an allocation function is always omitted. Only new-expressions that would otherwise result in a call to a replaceable global allocation function can be evaluated in constant expressions.
[edit] Placement new
If placement-params are provided, they are passed to the allocation function as additional arguments. Such allocation functions are known as «placement new», after the standard allocation function void * operator new ( std:: size_t , void * ) , which simply returns its second argument unchanged. This is used to construct objects in allocated storage:
Note: this functionality is encapsulated by the member functions of the Allocator classes.
When allocating an object whose alignment requirement exceeds __STDCPP_DEFAULT_NEW_ALIGNMENT__ or an array of such objects, the new-expression passes the alignment requirement (wrapped in std::align_val_t ) as the second argument for the allocation function (for placement forms, placement-params appear after the alignment, as the third, fourth, etc arguments). If overload resolution fails (which happens when a class-specific allocation function is defined with a different signature, since it hides the globals), overload resolution is attempted a second time, without alignment in the argument list. This allows alignment-unaware class-specific allocation functions to take precedence over the global alignment-aware allocation functions.
If a non-throwing allocation function (e.g. the one selected by new ( std:: nothrow ) T ) returns a null pointer because of an allocation failure, then the new-expression returns immediately, it does not attempt to initialize an object or to call a deallocation function. If a null pointer is passed as the argument to a non-allocating placement new-expression, which makes the selected standard non-allocating placement allocation function return a null pointer, the behavior is undefined.
[edit] Construction
The object created by a new-expression is initialized according to the following rules:
- For non-array type , the single object is constructed in the acquired memory area.
- If initializer is absent, the object is default-initialized.
- If initializer is a parenthesized list of arguments, the object is direct-initialized.
- If initializer is a brace-enclosed list of arguments, the object is list-initialized.
- If type or new-type is an array type, an array of objects is initialized.
- If initializer is absent, each element is default-initialized
- If initializer is an empty pair of parentheses, each element is value-initialized.
- If initializer is a brace-enclosed list of arguments, the array is aggregate-initialized.
- If initializer is a parenthesized list of arguments, the array is aggregate-initialized.
If initialization terminates by throwing an exception (e.g. from the constructor), if new-expression allocated any storage, it calls the appropriate deallocation function: operator delete for non-array type , operator delete [ ] for array type . The deallocation function is looked up in global scope if the new-expression used the :: new syntax, otherwise it is looked up in the scope of T , if T is a class type. If the failed allocation function was usual (non-placement), lookup for the deallocation function follows the rules described in delete-expression. For a failed placement new, all parameter types, except the first, of the matching deallocation function must be identical to the parameters of the placement new. The call to the deallocation function is made the value obtained earlier from the allocation function passed as the first argument , alignment passed as the optional alignment argument (since C++17) , and placement-params , if any, passed as the additional placement arguments. If no deallocation function is found, memory is not deallocated.
[edit] Memory leaks
The objects created by new-expressions (objects with dynamic storage duration) persist until the pointer returned by the new-expression is used in a matching delete-expression. If the original value of pointer is lost, the object becomes unreachable and cannot be deallocated: a memory leak occurs.
new expression
Создает и инициализирует объекты с динамическим сроком хранения , то есть объекты, время жизни которых не обязательно ограничено областью действия, в которой они были созданы.
Syntax
| :: (optional) new ( type ) initializer(optional) | (1) |
| :: (optional) new new-typeinitializer(optional) | (2) |
| :: (optional) new ( placement-params ) ( type ) initializer(optional) | (3) |
| :: (optional) new ( placement-params ) new-typeinitializer(optional) | (4) |
Инициализатор не является необязательным,если.
- type или new-type представляет собой массив неизвестных границ
- заполнитель используется в типе или новом типе, то есть auto или decltype(auto) (начиная с C++14), возможно, в сочетании с ограничением типа (начиная с C++20)
- шаблон класса используется в типе или новом типе, аргументы которого необходимо вывести
Explanation
В new попытках экспрессии выделить хранение , а затем попытку построить и инициализировать либо один неназванный объект или безымянный массив объектов в выделенном хранилище. Выражение new возвращает указатель prvalue на созданный объект или, если был создан массив объектов, указатель на начальный элемент массива.
Если type является типом массива, все измерения, кроме первого, должны быть указаны как положительное целочисленное константное выражение (до C++14) , преобразованное константное выражение типа std::size_t (начиная с C++14), но (только при использовании синтаксисы без скобок (2) и (4)) первое измерение может быть выражением интегрального типа, типа перечисления или типа класса с одной неявной функцией преобразования в целочисленный тип или тип перечисления (до С++ 14) любое выражение, конвертируемое в std::size_t (начиная с C++14). Это единственный способ напрямую создать массив с размером, определенным во время выполнения, такие массивы часто называют dynamic arrays :
Поведение не определено,если значение в первом измерении (при необходимости преобразованное в интегральный тип или тип перечисления)отрицательно.
В следующих случаях выражение,указывающее первое измерение,ошибочно:
- выражение имеет неклассный тип, и его значение до преобразования в std::size_t является отрицательным;
- выражение имеет тип класса и его значение после пользовательской функции преобразования и до второго стандартного преобразования отрицательно;
- значение выражения больше,чем некоторый установленный лимит реализации;
- значение меньше числа элементов массива, представленных в инициализаторе, заключенном в фигурные скобки (включая завершающий ‘\0’ в строковом литерале ).
Если значение в первом измерении ошибочно по какой-либо из этих причин,
- если после преобразования в std::size_t первое измерение является выражением основной константы , программа некорректна (выдается ошибка времени компиляции);
- В противном случае,если вызываемая функция распределения не перебрасывает,то новое выражение возвращает нулевой указатель нужного типа результата
- В противном случае new-выражение не вызывает функцию выделения, а вместо этого выдает исключение типа std::bad_array_new_length или производное от него
Первое измерение нуля приемлемо,и вызывается функция распределения.
Примечание: std::vector предлагает аналогичную функциональность для одномерных динамических массивов.
Allocation
Новое выражение выделяет память, вызывая соответствующую функцию выделения . Если type не является типом массива, имя функции будет operator new . Если type является типом массива, имя функции — operator new[] .
Как описано в функции распределения , программа C++ может предоставлять глобальные и зависящие от класса замены для этих функций. Если новое выражение начинается с необязательного оператора :: ,как в ::new T или ::new T[n] , замены, специфичные для класса, будут игнорироваться (функция просматривается в глобальной области видимости ). В противном случае, если T является типом класса, поиск начинается в области класса T .
При вызове функции распределения new-expression передает количество запрошенных байтов в качестве первого аргумента типа std::size_t , что в точности равно sizeof(T) для T , не являющегося массивом .
Распределение массива может привести к неопределенным накладным расходам, которые могут варьироваться от одного вызова к новому, если только выбранная функция распределения не является стандартной формой без выделения. Указатель, возвращаемый новым выражением, будет смещен на это значение от указателя, возвращаемого функцией распределения. Многие реализации используют служебные данные массива для хранения количества объектов в массиве, который используется выражением delete[] для вызова правильного количества деструкторов. Кроме того, если новое выражение используется для выделения массива char , unsigned char или std::byte (начиная с C++17) он может запросить дополнительную память у функции распределения, если это необходимо, чтобы гарантировать правильное выравнивание объектов всех типов, не превышающих запрошенный размер массива, если они впоследствии будут помещены в выделенный массив.
Новым выражениям разрешается исключать или объединять назначения,сделанные с помощью сменных функций распределения.В случае elision,хранилище может быть предоставлено компилятором без вызова функции выделения (это также позволяет оптимизировать неиспользуемые выражения).В случае объединения,выделение,сделанное новым выражением E1,может быть расширено для обеспечения дополнительного хранилища для другого нового выражения E2,если все нижеследующее верно:
1)Время жизни объекта,выделенного E1,строго содержит время жизни объекта,выделенного E2,2)E1 и E2 будут вызывать одну и ту же замещаемую функцию глобального распределения 3)Для функции распределения бросков исключения в E1 и E2 будут сначала попадать в один и тот же обработчик.
Обратите внимание, что эта оптимизация разрешена только при использовании новых выражений, а не любых других методов для вызова заменяемой функции распределения: delete[] new int[10]; можно оптимизировать, но operator delete(operator new(10)); не может.
Во время вычисления константного выражения вызов функции распределения всегда опускается. Только новые выражения, которые в противном случае привели бы к вызову заменяемой глобальной функции распределения, могут быть оценены в константных выражениях.
Placement new
Если placement-params размещения предоставлены, они передаются функции распределения в качестве дополнительных аргументов. Такие функции распределения известны как «размещение нового» после стандартной функции выделения void* operator new(std::size_t, void*) , которая просто возвращает свой второй аргумент без изменений. Это используется для создания объектов в выделенном хранилище:
Примечание: эта функциональность заключена в функции-члены классов Allocator .
При размещении объекта, требования к выравниванию которого превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__ , или массива таких объектов, выражение new передает требование выравнивания (обернутое в std::align_val_t ) в качестве второго аргумента функции распределения (для форм placement-params появляются после выравнивание, как третий, четвертый и т. д. аргументы). Если разрешение перегрузки не удается (что происходит, когда специфичная для класса функция распределения определена с другой сигнатурой, поскольку она скрывает глобальные переменные), выполняется повторная попытка разрешения перегрузки без выравнивания в списке аргументов. Это позволяет функциям распределения, не учитывающим выравнивание, иметь приоритет над глобальными функциями распределения, учитывающими выравнивание.
Если негенерирующая функция распределения (например, та, которая выбрана с помощью new(std::nothrow) T ) возвращает нулевой указатель из-за сбоя выделения, то новое выражение возвращается немедленно, оно не пытается инициализировать объект или вызвать функцию освобождения. Если нулевой указатель передается в качестве аргумента в выражение new-expression для нераспределяющего размещения, что приводит к тому, что выбранная стандартная функция распределения нераспределяющего размещения возвращает нулевой указатель, поведение не определено.
Construction
Объект,созданный новым выражением,инициализируется по следующим правилам:
- Для не массивного type единственный объект создается в полученной области памяти.
- Если инициализатор отсутствует, объект инициализируется по умолчанию .
- Если инициализатор представляет собой заключенный в скобки список аргументов, объект инициализируется напрямую .
- Если инициализатор представляет собой заключенный в скобки список аргументов, объект инициализируется списком .
- Если type или new-type-тип массива,инициализируется массив объектов.
- Если инициализатор отсутствует, каждый элемент инициализируется по умолчанию
- Если инициализатор представляет собой пустую пару скобок, каждый элемент инициализируется значением .
- Если инициализатор представляет собой заключенный в скобки список аргументов, массив инициализируется агрегатно .
- Если инициализатор представляет собой заключенный в скобки список аргументов, массив инициализируется агрегатно .
Если инициализация завершается генерацией исключения (например, из конструктора), если new-expression выделил какую-либо память, она вызывает соответствующую функцию освобождения : operator delete для type , отличного от массива , operator delete[] type массива . Функция освобождения просматривается в глобальной области видимости, если новое выражение использует синтаксис ::new , в противном случае она просматривается в области действия T , если T является типом класса. Если сбой функции выделения был обычным (не размещением), поиск функции освобождения следует правилам, описанным в выражении удаления .. Для неудавшегося нового размещения все типы параметров, кроме первого, соответствующей функции освобождения, должны быть идентичны параметрам нового размещения. При вызове функции освобождения используется значение, полученное ранее из функции распределения, переданное в качестве первого аргумента, выравнивание, переданное в качестве необязательного аргумента выравнивания (начиная с C++17), и placement-params , если таковой имеется, переданный в качестве дополнительного размещения. аргументы. Если функция освобождения не найдена, память не освобождается.
Memory leaks
Объекты, созданные с помощью новых выражений (объекты с динамической продолжительностью хранения), сохраняются до тех пор, пока указатель, возвращаемый новым выражением, не будет использован в соответствующем выражении удаления . Если исходное значение указателя потеряно, объект становится недоступным и не может быть освобожден: a memory leak occurs.
Это может произойти,если указатель назначен:
или если указатель выйдет за рамки:
или из-за исключения:
Чтобы упростить управление динамически расположенными объектами,результат нового выражения часто хранится в smart pointer : std::auto_ptr (до C ++ 17) std::unique_ptr или std::shared_ptr (начиная с C ++ 11). Эти указатели гарантируют, что выражение delete выполнено в ситуациях, показанных выше.
Keywords
Notes
Itanium C++ ABI требует, чтобы накладные расходы на выделение массива были равны нулю, если тип элемента созданного массива является тривиально разрушаемым. Как и MSVC.
Некоторые реализации (например, MSVC до VS 2019 v16.7) требуют ненулевых издержек выделения массива при нераспределенном массиве размещения new, если тип элемента не является тривиально разрушаемым, что больше не соответствует требованиям, начиная с CWG 2382 .
Нераспределяющее выражение массива размещения, создающее массив char , unsigned char или std::byte (начиная с C++17), может использоваться для неявного создания объектов в заданной области памяти: это завершает время жизни перекрывающихся объектов. с массивом, а затем неявно создает в массиве объекты неявных типов времени жизни.
Defect reports
Следующие отчеты о дефектах,изменяющих поведение,были применены ретроактивно к ранее опубликованным стандартам C++.
New (C++)
В языке программирования C++, new — оператор, обеспечивающий выделение динамической памяти в куче. За исключением формы, называемой «размещающей формой new», new пытается выделить достаточно памяти в куче для размещения новых данных и, в случае успеха, возвращает адрес свежевыделенной памяти. Однако, если new не может выделить память в куче, то он передаст (throw) исключение типа std::bad_alloc . Это устраняет необходимость явной проверки результата выделения.
Содержание
Синтаксис
Синтаксис new выглядит следующим образом:
где p_var — ранее объявленный указатель типа typename . typename может подразумевать собой любой фундаментальный тип данных или объект, определенный пользователем (включая, enum , class и struct ). Если typename — это тип класса, то вызывается конструктор по умолчанию для создания объекта.
Для инициализации новой переменной, созданной при помощи new нужно использовать следующий синтаксис:
где initializer — первоначальное значение, присвоенное новой переменной, а если type — тип класса, то initializer — аргумент(ы) конструктора.
new может также создавать массив:
В данном случае, size указывает размерность (длину) создаваемого одномерного массива. Адрес первого элемента возвращается и помещается в p_var , поэтому
означает значение n -го элемента (считая от нулевой позиции)
Память, выделенная при помощи new , должна быть освобождена при помощи delete , дабы избежать утечки памяти. Массивы, выделенные (созданные) при помощи new[] , должны освобождаться (уничтожаться) при помощи delete[] .
Инициализаторы не могут быть указаны для массивов, созданных при помощи new . Все элементы массива инициализируются при помощи конструктора по умолчанию для данного типа. Если тип не имеет конструктора по умолчанию, то произойдет ошибка при компиляции.
Placement new
Существует особая форма оператора new, называемая Placement new. Данный оператор не выделяет память и получает своим аргументом адрес на уже выделенную каким-либо образом память (например, на стеке или через malloc). Происходит размещение (инициализация) объекта путем вызова конструктора, и объект создается в памяти по указанному адресу.
Реализация
В компиляторах, придерживающимся стандарта ISO C++, в случае если недостаточно памяти для выделения, то код передает исключение типа std::bad_alloc . Выполнение всего последующего кода прекращается, пока ошибка не будет обработана в блоке try-catch или произойдет экстренное завершение программы. Программа не нуждается в проверке значения указателя; если не было передано исключение, то выделение прошло успешно. Реализованные операции определяются в заголовке <new> . В большинстве реализаций C++ оператор new также может быть перегружен для определения особого поведения.
Освобождение динамически выделенной памяти
Любая динамически выделенная память при помощи new должна освобождаться при помощи команды delete . Существует два варианта: один для массивов, другой — для единичных объектов.
Необходимо отметить, что компилятор не требует создания диагностического сообщения при некорректном использовании delete ; он в общем случае не может знать, когда указатель указывает на одиночный элемент, а когда — на массив элементов. Более того, использование не соответствующего освобождения по сути вызывает неопределённое поведение.
Повторное выделение памяти, выделенной при помощи new[]
В отличие от оператора realloc в языке Си, при помощи new[] невозможно напрямую перераспределить уже выделенную память. Для увеличения или уменьшения размера блока памяти нужно выделить новый блок нужного размера, скопировать данные из старой памяти и удалить старый блок. Стандартная библиотека языка C++ предусматривает поддержку динамического массива, который может быть увеличен или уменьшен в своем шаблонном классе .
См. также
- Распределители памяти
- malloc
- Пул памяти
- Синтаксис размещения
Ссылки
Wikimedia Foundation . 2010 .
Полезное
Смотреть что такое «New (C++)» в других словарях:
New — (n[=u]), a. [Compar.
(n[=u] [ e]r); superl. .] [OE. OE. newe, AS. niwe, neowe; akin to D. nieuw, OS. niwi, OHG. niuwi, G. neu, Icel. n[=y]r, Dan. & Sw. ny, Goth. niujis, Lith. naujas, Russ. novuii, Ir. nua, nuadh, Gael. nuadh, W.… … The Collaborative International Dictionary of English New — «New» Sencillo de No Doubt del álbum Retourn Of Saturn Formato CD Single Grabación 1999 Género(s) New Wave Duración 3:04 … Wikipedia Español
New I/O — New I/O, usually called NIO, is a collection of Java programming language APIs that offer features for intensive I/O operations. It was introduced with the J2SE 1.4 release of Java by Sun Microsystems to complement an existing standard I/O. NIO… … Wikipedia
New — (n[=u]), adv. Newly; recently. Chaucer. [1913 Webster] Note: New is much used in composition, adverbially, in the sense of newly, recently, to qualify other words, as in new born, new formed, new found, new mown. [1913 Webster]
, anew.… … The Collaborative International Dictionary of English New FM — City of license Newcastle Slogan Hottest Songs from the 80 s, 90 s and Today Frequency 105.3 MHz First air date 6 May 1989 ( … Wikipedia
NEW — ist: das IATA Kürzel für den New Orleans Lakefront Airport das Kfz Kennzeichen des Landkreises Neustadt an der Waldnaab new ist: das Kürzel für die Sprache Newari nach ISO 639 2 New ist ein englischer Familienname. Harry S. New (1858–1937), US… … Deutsch Wikipedia
New — Cette page d’homonymie répertorie les différents sujets et articles partageant un même nom. NEW, sigle composé des trois lettres N, E et W, peut faire référence à : Lakefront Airport, un aéroport régional de la Nouvelle Orléans en Louisiane … Wikipédia en Français
New — New, v. t. & i. To make new; to renew. [Obs.] [1913 Webster] … The Collaborative International Dictionary of English
New TV — est une chaîne de télévision fondée par Tahsin Khayat. Elle se situe à Beyrouth, spécifiquement à la Mazraa . Son service politique est dirigé par la journaliste Maria Maalouf … Wikipédia en Français