Главная страница » Что означает new char в с

Что означает new char в с

  • автор:

Объясните для чего нужен new char в СИ++. char *ch=new char[N]; gets(ch);

Чтобы выделить память под массив байтов.
P.S. GAdge7, это не ссылка, а указатель. И место не просто под char; а под массив из N char. Сам по себе такой указатель можно запросто создать без new — char *ch; создаст такой указатель.
йцу уйц — в целом этот код создает ВО ВРЕМЯ ВЫПОЛНЕНИЯ ПРОГРАММЫ массив для размещения в нем кодов N символов с указателем ch на его начало.

Сергей

оператор new выделяет в памяти компьютера МЕСТО под переменную с типом CHAR и передает АДРЕС этого места ссылке *ch. Без оператора NEW нельзя создать ссылку, т. к. место не выделено.

Name already in use

cpp-docs / docs / cpp / new-operator-cpp.md

  • Go to file T
  • Go to line L
  • Copy path
  • Copy permalink
  • Open with Desktop
  • View raw
  • Copy raw contents Copy raw contents

Copy raw contents

Copy raw contents

Attempts to allocate and initialize an object or array of objects of a specified or placeholder type, and returns a suitably typed, nonzero pointer to the object (or to the initial object of the array).

new-expression :
:: opt new new-placement opt new-type-id new-initializer opt
:: opt new new-placement opt ( type-id ) new-initializer opt

new-placement :
( expression-list )

new-declarator :
ptr-operator new-declarator opt
noptr-new-declarator

noptr-new-declarator :
[ expression ] attribute-specifier-seq opt
noptr-new-declarator [ constant-expression ] attribute-specifier-seq opt

new-initializer :
( expression-list opt )
braced-init-list

If unsuccessful, new returns zero or throws an exception. For more information, see The new and delete Operators. You can change this default behavior by writing a custom exception-handling routine and calling the _set_new_handler run-time library function with your function name as its argument.

For information on how to create an object on the managed heap in C++/CLI and C++/CX, see gcnew.

[!NOTE] Microsoft C++ Component Extensions (C++/CX) provides support for the new keyword to add vtable slot entries. For more information, see new (new slot in vtable)

When new is used to allocate memory for a C++ class object, the object’s constructor is called after the memory is allocated.

Use the delete operator to deallocate the memory allocated by the new operator. Use the delete[] operator to delete an array allocated by the new operator.

The following example allocates and then frees a two-dimensional array of characters of size dim by 10. When allocating a multidimensional array, all dimensions except the first must be constant expressions that evaluate to positive values. The leftmost array dimension can be any expression that evaluates to a positive value. When allocating an array using the new operator, the first dimension can be zero; the new operator returns a unique pointer.

The type-id can’t contain const , volatile , class declarations, or enumeration declarations. The following expression is ill-formed:

The new operator doesn’t allocate reference types because they’re not objects.

The new operator can’t be used to allocate a function, but it can be used to allocate pointers to functions. The following example allocates and then frees an array of seven pointers to functions that return integers.

If you use the operator new without any extra arguments, and compile with the /GX , /EHa , or /EHs option, the compiler generates code to call operator delete if the constructor throws an exception.

The following list describes the grammar elements of new :

new-placement
Provides a way of passing extra arguments if you overload new .

type-id
Specifies the type to be allocated; it can be either a built-in or user-defined type. If the type specification is complicated, it can be surrounded by parentheses to force the order of binding. The type may be a placeholder ( auto ) whose type is determined by the compiler.

new-initializer
Provides a value for the initialized object. Initializers can’t be specified for arrays. The new operator will create arrays of objects only if the class has a default constructor.

noptr-new-declarator
Specifies the bounds of an array. When allocating a multidimensional array, all dimensions except the first must be constant expressions that evaluate to positive values convertible to std::size_t . The leftmost array dimension can be any expression that evaluates to a positive value. The attribute-specifier-seq applies to the associated array type.

Example: Allocate and free a character array

The following code example allocates a character array and an object of class CName and then frees them.

Example: new operator

If you use the placement form of the new operator (the form with more arguments than the size), the compiler doesn’t support a placement form of the delete operator if the constructor throws an exception. For example:

Initializing objects allocated with new

An optional new-initializer field is included in the grammar for the new operator. This field allows new objects to be initialized with user-defined constructors. For more information about how initialization is done, see Initializers. The following example illustrates how to use an initialization expression with the new operator:

In this example, the object CheckingAcct is allocated using the new operator, but no default initialization is specified. So, the default constructor for the class, Acct() , is called. Then the object SavingsAcct is allocated the same way, except that it’s explicitly initialized to 34.98. Because 34.98 is of type double , the constructor that takes an argument of that type is called to handle the initialization. Finally, the non-class type HowMuch is initialized to 43.0.

If an object is of a class type and that class has constructors (as in the preceding example), the object can be initialized by the new operator only if one of these conditions is met:

The arguments provided in the initializer match the arguments of a constructor.

The class has a default constructor (a constructor that can be called with no arguments).

Explicit per-element initialization can’t be done when allocating arrays using the new operator; only the default constructor, if present, is called. For more information, see Default arguments.

If the memory allocation fails ( operator new returns a value of 0), no initialization is done. This behavior protects against attempts to initialize data that doesn’t exist.

As with function calls, the order in which initialized expressions are evaluated isn’t defined. Furthermore, you shouldn’t rely on these expressions being evaluated completely before the memory allocation takes place. If the memory allocation fails and the new operator returns zero, some expressions in the initializer may not be evaluated completely.

Lifetime of objects allocated with new

Objects allocated with the new operator aren’t destroyed when the scope in which they’re defined is exited. Because the new operator returns a pointer to the objects it allocates, the program must define a pointer with suitable scope to access and delete those objects. For example:

Once the pointer AnotherArray goes out of scope in the example, the object can no longer be deleted.

The new-expression (the expression containing the new operator) does three things:

Locates and reserves storage for the object or objects to be allocated. When this stage is complete, the correct amount of storage is allocated, but it’s not yet an object.

Initializes the object(s). Once initialization is complete, enough information is present for the allocated storage to be an object.

Returns a pointer to the object(s) of a pointer type derived from new-type-id or type-id . The program uses this pointer to access the newly allocated object.

The new operator invokes the function operator new . For arrays of any type, and for objects that aren’t class , struct , or union types, a global function, ::operator new , is called to allocate storage. Class-type objects can define their own operator new static member function on a per-class basis.

When the compiler encounters the new operator to allocate an object of type T , it issues a call to T::operator new( sizeof(T) ) or, if no user-defined operator new is defined, ::operator new( sizeof(T) ) . It’s how the new operator can allocate the correct amount of memory for the object.

[!NOTE] The argument to operator new is of type std::size_t . This type is defined in <direct.h>, <malloc.h>, <memory.h>, <search.h>, <stddef.h>, <stdio.h>, <stdlib.h>, <string.h>, and <time.h>.

An option in the grammar allows specification of new-placement (see the Grammar for new Operator). The new-placement parameter can be used only for user-defined implementations of operator new ; it allows extra information to be passed to operator new . An expression with a new-placement field such as T *TObject = new ( 0x0040 ) T; is translated to T *TObject = T::operator new( sizeof( T ), 0x0040 ); if class T has member operator new , otherwise to T *TObject = ::operator new( sizeof( T ), 0x0040 ); .

The original intention of the new-placement field was to allow hardware-dependent objects to be allocated at user-specified addresses.

[!NOTE] Although the preceding example shows only one argument in the new-placement field, there’s no restriction on how many extra arguments can be passed to operator new this way.

Even when operator new has been defined for a class type T , you can use the global operator new explicitly, as in this example:

The scope-resolution operator ( :: ) forces use of the global new operator.

Difference between char[] and new char[] when using constant lengths

So this may seem like a widely-answered question, but I’m interested more in the internals of what exactly happens differently between the two.

Other than the fact that the second example creates not only the memory, but a pointer to the memory, what happens in memory when the following happens:

And more directly related to why I asked this question, how come I can do

EDIT Should have mentioned I’m getting this compiler error on VC++ (go figure. )

EDIT 2: Should have posted the exact code I was working with. This error is produced when the constant length for the dynamically allocated array is calculated with run-time values.

Assuming random(a,b) returns an int between a and b ,

8 Answers 8

The difference is the lifetime of the array. If you write:

then the array has a lifetime of the block it’s defined in (if it’s defined in block scope), of the class object which contains it (if it’s defined in class scope) or static lifetime (if it’s defined at namespace scope). If you write:

, then the array has any lifetime you care to give it—you must explicitly terminate its lifetime with:

And with regards to your last question:

is perfectly legal, and should compile. Where there is a difference:

The reason for the difference is mostly one of compiler technology and history: in the very early days, the compiler had to know the length in order to create the array as a local variable.

what happens in memory when the following happens:

Assuming a typical but somewhat simplified C++ implementation, and that the above code appears in a function:

The stack pointer is moved by 5 bytes, to make a 5-byte space. The name a now refers to that block of 5 bytes of memory.

The stack pointer is moved by sizeof(char*) , to make space for b . A function is called, that goes away and allocates 5 bytes from a thing called the «free store», basically it carves 5 or more bytes off a big block of memory obtained from the OS, and does some book-keeping to ensure that when you free those bytes with delete[] , they will be made available for future allocations to re-use. It returns the address of that allocated block of 5 bytes, which is stored into the the space on the stack for b .

The reason that the second is more work than the first is that objects allocated with new can be deleted in any order. Local variables (aka «objects on the stack») are always destroyed in reverse order of being created, so less book-keeping is needed. In the case of trivially-destructible types, the implementation can just move the stack pointer by the same distance in the opposite direction.

To remove some of the simplifications I made: the stack pointer isn’t really moved once for each variable, possibly it’s only moved once on function entry for all variables in the function, in this case the space required is at least sizeof(char*) + 5 . There may be alignment requirements on the stack pointer or the individual variables which mean it’s not moved by the size required, but rather by some rounded-up amount. The implementation (usually the optimizer) can eliminate unused variables, or use registers for them instead of stack space. Probably some other things I haven’t thought of.

The language rule is reasonably simple: the size of an array must be a constant expression. If a const int variable has an initializer in the same TU, and the initializer is a constant expression, then the variable name can be used in constant expressions. random(1,5) is not a constant expression, hence len1 cannot be used in constant expressions. 5 is a constant expression, so len2 is fine.

What the language rule is there for, is to ensure that array sizes are known at compile time. So to move the stack, the compiler can emit an instruction equivalent to stack_pointer -= 5 (where stack_pointer will be esp , or r13 , or whatever). After doing that, it still «knows» exactly what offsets every variable has from the new value of the stack pointer — 5 different from the old stack pointer. Variable stack allocations create a greater burden on the implementation.

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++.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *