In C++, is 'new' an operator or an expression or some kind of keyword? a similar question that comes in mind is, should i call '=' an operator or expression?
C++ separates the notion of memory allocation and object lifetime. This is a new feature compared to C, since in C an object was equivalent to its memory representation (which is called "POD" in C++).
An object begins its life when a constructor has completed, and its life ends when the destructor has completed. For an object of dynamic storage duration, the life cycle thus consists of four key milestones:
Memory allocation.
Object construction.
Object destruction.
Memory deallocation.
The standard way in C++ to allocate memory dynamically is with the global ::operator new(), and deallocation with ::operator delete(). However, to construct an object there is only one method: A new expression:
T * p = new T;
This most common form of the new expression does allocation and construction in one step. It is equivalent to the broken down version:
void * addr = ::operator new(sizeof(T));
T * p = new (addr) T; // placement-new
Similarly, the delete expression delete p; first calls the destructor and then releases memory. It is equivalent to this:
p->~T();
::operator delete(addr);
Thus, the default new and delete expressions perform memory allocation and object construction in one wash. All other forms of the new expression, collectively called "placement new", call a corresponding placement-new operator to allocate memory before constructing the object. However, there is no matching "placement delete expression", and all dynamic objects created with placement-new have to be destroyed manually with p->~T();.
In summary, it is very important to distinguish the new expression from the operator new. This is really at the heart of memory management in C++.
It's all of those.
2.13 Table 4 explicitly lists new as a keyword.
5.3.4 Introduces the new-expression. This is an expression such as new int(5) which uses the new keyword, a type and an initial value.
5.3.4/8 Then states that operator new is called to allocate memory for the object created by the new-expression
= works quite the same. Each class has an operator= (unless explicitly deleted), which is used in assignment expressions. We usually call a=5; just an assignment, even when it's technically "an expression statement containing an assignment expression."
new is operator. You can overload it and write your own version of it. Also I think that = is operator. Expression is more complex thing which consist of operators, variables, function calls etc. And please try to get C++ language standard. It must describe all things you mentioned.
Related
Section "11.2.4 Overloading new" ends with:
"There is no special syntax for placement of arrays. Nor need there be since arbitrary types can be allocated by placement new. However, an operator delete can be defined for arrays".
If I understand it correctly, what is being said is that for arrays, we use the usual placement new syntax, which would invoke the appropriate operator new[]. But, what I don't understand is the last sentence. What is he trying to say there? Afaik, we can specify both operator new and operator delete for arrays.
There is a special allocator for arrays (operator new[]()) but it is not dependent on a special syntax.
In the following code
new T();
or
new (p) T();
The compiler will generate a call to either operator new(...) or operator new[](...) depending on whether T is an array type. There is no syntactic difference in the new-expression.
(Now, there is a special syntax for a new-expression with a runtime size... but invocation of operator new[]() is not limited to scenarios with a runtime size)
In contrast to new, for delete the same pointer type is compatible with both scalar and array. So you the programmer must tell the compiler which you want via
delete p;
vs
delete [] p;
There is no automatic translation to delete[] based on recognition of an array type.
I'm using llvm lately, and I found that new statements in cpp are translated to _Znam in llvm IR, I know that
new in cpp also call the function _Znwm, and new [] call _Znam, so what's the difference between the functionality of these two functions?
What if I use _Znwm to allocate space for an array?
Example
a = new int*[10];
is compiled as
%2 = call i8* #_Znam(i64 80) #2
_Znwm and _Znam are just mangled names for the functions
operator new(std::size_t)
and
operator new[](std::size_t)
respectively.
An (non-placement) array new expression calls the latter, while a (non-placement) non-array new expression calls the former to allocate memory.
These functions can be replaced by the user, but a default implementation is provided by the standard library. The default implementation of the array version simply calls the non-array version since C++11 and the non-array version allocates memory of the passed size, aligned suitably for all non-overaligned types, in some unspecified way, throwing the exception std::bad_alloc if allocation fails and otherwise returning a non-null pointer to the beginning of the allocated block.
So it behaves similar to std::malloc, except that the latter returns a null pointer if allocation fails, rather than throwing an exception. It is unspecified, but likely, that the default operator new implementation just uses malloc internally to do the allocation.
malloc should not call operator new or operator new[], so I don't know why you think that it would translate to that in IR.
I don't think there is anything LLVM-specific here. Which allocation function is called is specified by the C++ standard. Only the names are mangled in an implementation-defined manner.
Also note that these calls are not all that the new expressions translate to. After calling operator new/operator new[] the new expression will also construct objects in the memory, which may require constructor calls to stores of values.
I know of storage classes in both C and C++ (static, extern, auto, register, C++ also adds mutable and some compiler-specific ones) but I can't figure out what a storage allocator is. I don't think it's referred to memory allocators implementable on STL, what is it in simple terms?
It's whatever is behind operator new and operator delete (not to be confused with the new operator and the delete operator). operator new allocates memory from the free store, and operator delete releases memory previously allocated by operator new for possible reuse. When code does foo *ptr = new foo (new operator), the compiler generates code that calls operator new to get the right number of bytes of storage, then calls the constructor for foo. When code does delete ptr (delete operator) the compiler calls the destructor for foo, then calls operator delete to release the memory.
Note that this is how the term is used in the C++03 standard. In the C++11 standard it is also used to refer to standard allocators.
In the C++ standard, that term is used to refer to the allocator class used by STL-style containers - either std::allocator, or a user-defined custom allocator that meets the requirements given by C++11 17.6.3.5.
However, it's not a formally defined term, and also appears once referring to the implementation of the free store - that is, the dynamic storage allocated by new.
[NOTE: I'm referring to the current (2011) language specification. As noted in the comments, historical versions of the specification apparently only used the term (informally) to refer to the free store]
When considering something along the lines of
auto x = new T;
Does the Standard enforce that the memory must come from operator new- class-specific or global? i.e., there is no way a conforming implementation, given a lack of a class-specific operator new, could get the memory from anywhere except the global operator new?
I think you have it the wrong way round.
The expression new T always consists of two steps:
A suitable operator new is searched for. If one exists in the class T, that one is taken, otherwise the global one is taken. The global one always exists, as this is mandated by the standard (so you can never "define" it (since it is already defined), but you can replace it).
You can say ::new T to always pick the global operator new unconditionally.
Once the allocation function has been called and succeeded, the object is constructed in that memory.
If you say new (a, b, c) T, then the same happens, only that in step 1 we are now looking for an operator new overload with the appropriate signature.
It is not guaranteed to be ::operator new, as the memory can come from a class specific operator new instead, but if no such class-specific version exists, then the global version will be used. The relevant part of the standard is [expr.new]/8:
A new-expression obtains storage for the object by calling an allocation function. ... the allocation function’s name is operator new ...
Does the Standard enforce that the memory must come from operator new- class-specific or global?
Yes, it does.
§5.3.4 [expr.new]:
p8 A new-expression obtains storage for the object by calling an allocation function (3.7.4.1). [...] If the allocated type is a non-array type, the allocation function’s name is operator new [...].
p9 If the new-expression begins with a unary :: operator, the allocation function’s name is looked up in the global scope. Otherwise, if the allocated type is a class type T or array thereof, the allocation function’s name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a class type, the allocation function’s name is looked up in the global scope.
This MSDN page mentions that there're nothrow versions of new and delete. nothrow new is quite a known thing - returns null instead of throwing an exception if memory allocation fails. But what is nothrow delete mentioned there?
They are probably referring to the raw memory allocation functions operator new and operator delete.
When you invoke a specific version of placement new-expression (i.e. new-expression with extra parameters; they all are officially referred to as placement forms of new) and the memory allocation function operator new succeeds, but the process fails later for some other reason (the constructor throws), the implementation has to abort the process and automatically release the allocated memory by calling the appropriate version of operator delete. "Appropriate version" of operator delete in this case is the version that has the same set of parameters as the operator new function previously used for memory allocation (except for the very first parameter, of course).
This applies to nothrow version of operator new as well. When you use a nothrow form of new-expression, it calls a nothrow version of operator new and then constructs the object in the allocated memory. If the constructor fails (throws), the implementation of the new-expression releases allocated memory with the help of nothrow version of operator delete. This is basically the only reason for this version of operator delete to exist.
In other words, the nothrow version of operator delete exists for very specific internal purposes. You should not normally want to call it yourself and, maybe, you don't really need to know about its existence. However, it is worth knowing that for the reasons described above, whenever you create your own version of operator new with extra parameters, it is always a good idea to provide a matching version of operator delete with the same set of extra parameters.