Just came across this. I can't believe it compiles, but it does. What kind of string initialization is this? And why do this?
std::string* name = new std::string[12];
This is a dynamic C-style array syntax, which was in place before std::vector obsoleted all but the small fraction of this usage - and since C++11 even that smallest usage has vanished.
This code dynamically creates and initializes 12 empty strings and sets name pointer to point to the very first of them. Now those strings can be accessed with [] operator, for example:
std::cout << name[0] << "\n";
Will output empty string.
There should never be any reason to use this construct, though, and instead
std::vector<std::string> name(12);
should be used.
What ... is this?
That is a new-expression. It allocates an object in the free store. More specifically, this expression allocates an array of 12 std::string objects.
What kind of ... initialization is this?
The strings of the array are default-initialized.
And why do this?
The scope of this question is unclear...
Why use an array?
Because arrays are the most efficient data structure. They incur zero space overhead and (depending on situation) interact well with processor caching.
Why allocate a dynamic array (from the free store)?
Because the size of an automatic array must be known at compile time. The size of a dynamic array does not need to be known until runtime. Of course, your example uses a compile time constant size for the array, so dynamic allocation is not necessary for that reason.
Also because the memory for automatic variables is limited (one to few megabytes on typical desktop systems). As such, large objects such as arrays that contain many objects must be allocated form the free store. An array of 12 strings is not significantly large in relation to the size of memory that is usually available for automatic objects.
Also because dynamic objects are not automatically destroyed at the end of current scope, so their lifetime is more flexible than automatic or static objects. Of course, this is as much a reason to not use dynamic objects: They are not destroyed automatically, and managing their lifetime is difficult and proving the correctness of a program that uses dynamic memory can be very difficult.
Why use a new expression to allocate an array
There's typically no reason to do so. The standard library provides a RAII container that handles the lifetime of the dynamically allocated array: std::vector.
This code is allocating an array of 12 std::string objects and storing the pointer to the first element of the array in the name variable.
std::string* name = new std::string[12];
The new expression allocates an array of 12 std::string objects with dynamic storage duration. Each std::string object in the array is initialized via its default constructor.
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.
The pointer to the initial element of the array is then stored in name so that you can access the elements of the array using the [] subscript operator.
Related
Again with placement new I've found an example on this forum like this:
char *buf = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi"); // placement new
string *q = new string("hi"); // ordinary heap allocation
But I think here buf is a pointer to an allocated and Constructed dynamic array of default-init characters. So the characters in the array are default initialized and have an indeterminate values.
I guess using the placement new in the second line will constructs objects on the previously constructed array of objects.
Why the user didn't call operator new on the array allocation rather than using new expression?:
char *buf = static_cast<char*>(operator new[](sizeof(string)));
After all I think if buff is a pointer to a dynamic array of non-default-constructible objects then the code will fail to compile using the new expression rather than using the operator new function.
Are my guesses correct?
Here is the link to the original answer:
What uses are there for "placement new"?
Why the user didn't call operator new on the array allocation rather than using new expression?:
We cannot answer that question because we aren't that user. You should ask that from the user - though given that the example was written in 1998 it might not be easy to contact them. My guess: They didn't know that non-placement operator new exists or they didn't know what it is used for. Reusing the memory of an array of char is an intuitive choice in such case.
Note that the example of creating a singular dynamic std::string object makes little sense in the first place (I'm assuming that's what string in the example is).
I have a similar question to you: Why are you using operator new[] in your suggestion and not operator new? Even more importantly, why not use an allocator?
Are my guesses correct?
Correct.
Correct.
This is a question and not a guess. I covered it above.
It would fail. But that's irrelevant since char is default constructible.
char is an object type that is both fundamental and trivial. Creating one doesn't, in practice, touch memory, and making an array of them does not either.
char* foo = new char[10];
and
char *foo = static_cast<char*>(operator new[](10));
end up doing exactly the same thing in machine code, except the second one is a lot more verbose.
There are some subtle differences in the abstract machine; in one a bunch of chars are created, in the other the other they are not on that line. Coming up with a case where that matters is going to require a fair bit of language lawyering effort (I am thinking disposal may be different, and some access might be different, especially in standard versions before c++ fixed the malloc problem).
After all I think if buff is a pointer to a dynamic array of non-default-constructible objects then the code will fail to compile using the new expression rather than using the operator new function.
Sure, but the cast would be code smell, and the point of buf is to be storage for the later placement new. I guess it already is,
void *foo = operator new[](10);
is less bonkers.
Just because you can static cast does not mean you should.
operator new[](sizeof(string)) that's something odd, its incorrect syntax for creating an object. In best case scenario it creates an object in memory implicitly (if operator new implemented as std::malloc call and object is a POD type), without initializing or constructing one. All you can do in that case is to static_cast<char*>(new string); The offered line just would create a string object in dynamic storage and then make it anonymous by replacing type of pointer by char*.
Thing is, for placement new buf is not necessary to point to dynamic memory. It can be a static buffer.It can be a pointer to memory location within a rather large storage used to store multiple objects, a memory pool. New object would constructed at given location.
Note that in case of placement new std::string's data storage is still behaves as it usually does - it allocates character data in dynamic memory. To use some memory pool, programmer should provide appropriate allocator and that's one of purposes for placement new operator.
No, buf isn't an array of objects. It's an array of characters, so basically an array of bytes. And while it was allocated with an array new, its basically being used as a byte pointer.
The use of placement new is if you want to allocate an object at an exact location, but you want to do so following all the rules of C++ object allocation- so constructors called and vtables set up. The usual use case for this is if you're doing your own custom memory allocation and reusing existing memory addresses. Firmware may use this to reuse memory as a pool. Or an RTOS may use it so that it doesn't exceed memory restrictions for a task.
This is actually a poor example of how its used because of that. You'd never new an array then placement new into it. You'd have a pointer to a block of allocated memory lying around, and you'd use placement new into that.
I would like to have a class that contains an array member, but the constructor lets me set the size of an array member.
Is this doable? I do not thing I need dynamic allocation, since once the class instances are created, there is no need for the array to change size, it is just that each class instance will have a different size.
Despite several comments suggest that this would be impossible, it is actually not impossible.
The simplest way, of course, is to use an indirection and allocate the array during construction just the normal way (with a = new type[size] and calling delete[] a - not delete a - in the destructor).
But if for some reason you really do not want to have the array data being allocated separately from your object, you can use placement-new to construct your object into a pre-allocated buffer that is large enough to contain all your elements. This avoids a separate allocation for your array and you can still have dynamic size.
I would not recommend using this technique, though, unless you really have a demanding use case for it.
I'm reading about dynamic arrays (specifically at https://www.learncpp.com/cpp-tutorial/dynamically-allocating-arrays/), and it seems to me that dynamic arrays are not actually dynamic, in that the size allocated for them cannot be changed.
If I am understanding correctly, the main use or point of dynamic arrays vs fixed arrays is that dynamic arrays will be allocated on the heap rather than the stack, and therefore can be larger. The terms "dynamic" and "fixed" give me the impression that one can be changed and the other cannot, but it doesn't seem to be the case.
Is this correct, or am I misunderstanding something about dynamic vs fixed arrays?
Dynamic arrays are dynamic i.e. they have dynamic lifetime / dynamic storage (i.e. they are stored in free store aka "heap").
Dynamic arrays are also dynamic in the sense that unlike array variables, their size can be determined at runtime i.e. it doesn't need to be compile time constant. Example:
int size;
std::cin >> size;
auto ptr = std::make_unique<int[]>(size); // dynamic
int arr[size]; // ill-formed
You're correct in that the size of a (dynamic) array cannot change through its lifetime. Thus, a dynamic array in C++ isn't the abstract data structure by the same name, also known by names "growable array", "resizable array", "dynamic table", "mutable array", or "array list". The C++ standard library has implementation of that data structure by the name std::vector.
"Dynamic" refers not to size, but to allocation method. In most C++ implementations there's several methods of storing data, but the two relevant here are local, as in on the stack, and dynamic, as in on the heap.
Dynamic tends to mean "allocated with new" or a similar mechanism, while stack allocations happen implicitly.
X* x = new X[20]; // "Dynamic" array
X x[20]; // Local array
Neither of these can be easily resized.
A dynamic array can be reallocated and resized, while a stack one cannot, the size on the stack is fixed. This makes dynamic arrays more flexible in that regard, but it's not something that comes for free, you need to do a lot of work to implement that to ensure that your newly allocated object is consistent and that all pointers to it have been updated.
Additionally, the lifetime is different, as dynamically allocated structures have an indefinite lifetime, as the programmer you control that, while local variables have a scope-defined lifetime that is non-negotiable. When you exit the scope, they're gone.
Dynamic allocations come with considerable overhead on the part of the programmer, you're responsible for managing that lifecycle or delegating it to a wrapper that can do it for you, like a smart pointer.
In modern C++ using actual low-level arrays is difficult and error-prone which is why std::vector is typically used instead. It provides way more guarantees and helps manage lifecycles for you if used effectively. The implementation of these manages resizing, and object deletion for you.
Consider a c++ class named A. What are the pros/cons to use an array of objects:
std::array<A, 10>
instead of an array of pointers:
std::array<A*, 10>
Here are important differences:
Array of objects:
Memory of the objects is managed by std::array.
Objects are stored in contiguous memory (good cache efficiency)
All objects are of same type
All objects exist
Assigning an element makes a copy of the object
Array of pointers:
Memory of the objects that are pointed to is not managed by the std::array which contains the pointers.
You can store pointers to a common base of polymorphic types
Pointers can have nullptr value i.e. does not point to any object
Assigning an element does not make a copy of the object which is pointed to
Whether any of these things is a pro or a con depends on your use case.
And now for the opinion based part, as a hint to beginners: In my opinion, the fact that the memory is managed by the array makes it clear that the array "owns" the objects. It's often not clear who owns the objects that are pointed to by the pointers. The clarity of ownership, combined with the cache efficiency which is always a bonus, makes the array of objects a good default choice when you are not sure. Use objects in arrays when you can, pointers when you need to. And when you need pointers, consider whether std::unique_ptr is appropriate.
if you don't want to use STL array, you can use your own array
1) A array[10]
or
2) A* array[10]
For #1, class A must have a default constructor.
A needs more memory to hold object
Whenever you assigned an object to any index of the array, copy constructor gets called
Compilation time required is more
For #2 There is no need of constructor
sizeof(array) = size of pointer * 10
compilation time required is less
There is no need of default constructor or copy constructor
Is there a any difference in terms of memory allocation between
struct_type * mystruct = new struct_type();
and
struct_type *mystruct = new struct_type[1];
?
It depends on what you mean by "difference in memory allocation".
Firstly, new and new[] are two independent memory allocation mechanisms, which can (and will) allocate memory with different internal layout, e.g. with different implementation-dependent household information associated with allocated memory block. It is important to remember that the first allocation has to be paired with delete and the second - with delete []. Also, for this reason, in a typical implementation the second allocation might consume more memory than the first.
Secondly, the initializer syntax () you used in the first allocation triggers value-initialization of the allocated object. Meanwhile, in your second allocation you supplied no initializer at all. Depending on the specifics of struct_type class, this can lead to significant differences in initialization. For example, if struct_type is defined as struct struct_type { int x; }, the first allocation is guaranteed to set mystruct->x to zero, while the second one will leave a garbage value in mystruct->x. You have to do new struct_type[1]() to eliminate this (probably unintended) difference.
They will allocate same amount visible/usable of memory, namely memory required to hold one object. But the semantics are different, former is a pointer to single object, while latter is an array containing one object. And when de-allocating you should use
delete mystruct;
in first case while
delete []mystruct;
in second case.
Another difference is compiler must hold some book-keeping information about the latter case, for example it must know the number of items in the array, so that it can be deleted correctly. And of course your structure must have a default constructor in to be used in latter case.
The first line would create a structure object and return its address to your pointer.
The second line would create an array of 1 structure object and return the starting address of the array to your pointer
I think there is no difference in terms of memory allocation between these two lines of code.