I learned about the stack and the heap recently, and something doesn't make sense.
I read that std::array is stored on the stack even though the count and size of the elements of the size is unknown.
the same way you can't read input of unknown length to the stack from the user.
what am I missing here?
To create an std::array you have to specify in its template (or let the compiler deduce) both the count and the type of the elements stored. That makes the size known at compile time, hence it can be instantiated on the stack.
std::array is nothing but a thin wrapper around C-style arrays. The size is fixed, it cannot grow nor shrink.
Related
I am studying C++ reading Stroustrup's book that in my opinion is not very clear in this topic (arrays). From what I have understood C++ has (like Delphi) two kind of arrays:
Static arrays that are declared like
int test[3] = {10,487,-22};
Dynamic arrays that are called vectors
std::vector<int> a;
a.push_back(10);
a.push_back(487);
a.push_back(-22);
I have already seen answers about this (and there were tons of lines and concepts inside) but they didn't clarify me the concept.
From what I have understood vectors consume more memory but they can change their size (dynamically, in fact). Arrays instead have a fixed size that is given at compile time.
In the chapter Stroustrup said that vectors are safe while arrays aren't, whithout explaining the reason. I trust him indeed, but why? Is the reason safety related to the location of the memory? (heap/stack)
I would like to know why I am using vectors if they are safe.
The reason arrays are unsafe is because of memory leaks.
If you declare a dynamic array
int * arr = new int[size]
and you don't do delete [] arr, then the memory remains uncleared and this is known as a memory leak. It should be noted, ANY time you use the word new in C++, there must be a delete somewhere in there to free that memory. If you use malloc(), then free() should be used.
http://ptolemy.eecs.berkeley.edu/ptolemyclassic/almagest/docs/prog/html/ptlang.doc7.html
It is also very easy to go out of bounds in an array, for example inserting a value in an index larger than its size -1. With a vector, you can push_back() as many elements as you want and the vector will resize automatically. If you have an array of size 15 and you try to say arr[18] = x,
Then you will get a segmentation fault. The program will compile, but will crash when it reaches a statement that puts it out of the array bounds.
In general when you have large code, arrays are used infrequently. Vectors are objectively superior in almost every way, and so using arrays becomes sort of pointless.
EDIT: As Paul McKenzie pointed out in the comments, going out of array bounds does not guarantee a segmentation fault, but rather is undefined behavior and is up to the compiler to determine what happens
Let us take the case of reading numbers from a file.
We don't know how many numbers are in the file.
To declare an array to hold the numbers, we need to know the capacity or quantity, which is unknown. We could pick a number like 64. If the file has more than 64 numbers, we start overwriting the array. If the file has fewer than 64 (like 16), we are wasting memory (by not using 48 slots). What we need is to dynamically adjust the size of the container (array).
To dynamically adjust the capacity of an array, a new larger array must be created, then elements copied and the old array deleted.
The std::vector will adjust its capacity as necessary. It handles the dynamic allocation of memory for you.
Another aspect is the passing of the container to a function. With an array, you need to pass the array and the capacity. With std::vector, you only need to pass the vector. The vector object can be queried about its capacity.
One Security I can see is that you can't access something in vector which is not there.
What I meant by that is , if you push_back only 4 elements and you try to access index 7 , then it will throw back an error. But in array that doesn't happen.
In short, it stops you from accessing corrupt data.
edit :
programmer has to compare the index with vector.size() to throw an error. and it doesn't happne automatically. One has to do it by himself/herself.
I want to create an array which is not on the heap, but on the stack. The size of my array will be based on the number of lines in a file.
I found this SO post:
Why aren't variable-length arrays part of the C++ standard?
Is there still no way to create an array on the stack where the size is determined by something else, other than a const?
No, you can't create an array on the stack unless its size is known at compile time. Not just const, but compile-time constant.
c++11 uses template to define the max_size of the array (eg. std::array<int, 5> a1;) but not constructor. (eg. std::array<int>(5) a1;)
Since template is going to generate code for the class, and if I have a lot of arrays just differs in sizes, there'll be a lot of code to be generated.
(1. It may cause increase in compile time.
2. It may cause the expension of the code part of the executable file.)
Because if it didn't, it wouldn't be able to be what it is.
std::array is an array. Not a dynamically-sized array. Not a runtime-sized array. It is an array, much like int arr[5].
C++ is a statically typed language, which means that C++ types must have a compile-time defined size. arr in the above example has a size; if you do sizeof(arr), you will get sizeof(int) * 5. sizeof(std::array<int, 5>) has a size as well, which is defined by the number of elements in it. Therefore, the size must be a compile-time defined quantity, since it factors into the compile-time defined size.
The differences between std::array and regular arrays are:
Arrays will decay into pointers implicitly. std::array does not; you need to explicitly call a function to do that.
Arrays are language arrays; std::array, to the language, is a struct which contains an array.
if I have a lot of arrays just differs in sizes, there'll be a lot of code to be generated.
Yes, you might. Then again... is this a serious concern? Have you really looked at a std::array implementation?
There's not much there. T operator[](int index) { return elems[index]; } I don't think getting a couple hundred instantiations of that function is going to be a problem. Same goes for begin, size, empty, etc. You're talking about code that will almost certainly be inlined.
std::array is meant as a thin wrapper over a fixed-sized array. For a dynamically-sized array, there is std::vector.
One benefit of std::array is that it allocates memory on the stack (unless you declare a global object) with minimal overhead.
If the array size was determined by a constructor parameter, allocation would have to be on the heap and in general the resulting object would be less efficient in terms of memory usage and performance.
What is the exact difference between dynamic arrays and vectors. It was an interview question to me.
I said both have sequential memory.
Vectors can be grown in size at any point in the code. He then said even dynamic arrays can be grown in size after creating.
I said vectors are error free since it is in the standard library. He said he will provide as .so file of dynamic arrays which is error free and has all the qualities on par with STL.
I am confused and didn't answer the exact difference. When I searched on Internet, I had seen the above statements only.
Can someone please explain me the exact difference? And what was the interviewer expecting from me?
He said he will provide as .so file of dynamic arrays which is error free and has all the qualities on par with STL.
If his dynamic array class does the same as std::vector (that is: it implements RAII to clean up after itself, can grow and shrink and whatever else std::vector does), then there's only one major advantage std::vector has over his dynamic array class:
std::vector is standardized and everybody knows it. If I see a std::vector in some piece of code, I know exactly what it does and how it is supposed to be used. If, however, I see a my::dynamic_array, I do not know that at all. I would need to have to look at its documentation or even — gasp! — implementation to find out whether my_dynamic_array::resize() does the same as std::vector::resize().
A great deal here depends on what he means by a "dynamic array". Most people mean something where the memory is allocated with array-new and freed with array-delete. If that's the intent here, then having qualities on a par with std::vector simply isn't possible.
The reason is fairly simple: std::vector routinely allocates a chunk of memory larger than necessary to hold the number of elements currently being stored. It then constructs objects in that memory as needed to expand. With array-new, however, you have no choice -- you're allocating an array of objects, so if you allocate space for (say) 100 objects, you end up with 100 objects being created in that space (immediately). It simply has no provision for having a buffer some part of which contains real objects, and another part of which is just plain memory, containing nothing.
I suppose if yo want to stretch a point, it's possible to imitate std::vector and still allocate the space with array-new. To do it, you just have to allocate an array of char, and then use placement new to create objects in that raw memory space. This allows pretty much the same things as std::vector, because it is nearly the same thing as std::vector. We're still missing a (potential) level of indirection though -- std::vector actually allocates memory via an Allocator object so you can change exactly how it allocates its raw memory (by default it uses std::allocator<T>, which uses operator new, but if you wanted to, you could actually write an allocator that would use new char[size], though I can't quite imagine why you would).
You could, of course, write your dynamic array to use an allocator object as well. At that point, for all practical purposes you've just reinvented std::vector under a (presumably) new name. In that case, #sbi is still right: the mere fact that it's not standardized means it's still missing one of the chief qualities of std:::vector -- the quality of being standardized and already known by everybody who knows C++. Even without that, though, we have to stretch the phrase "dynamic array" to (and I'd posit, beyond) the breaking point to get the same qualities as std::vector, even if we ignore standardization.
I expect they wanted you to talk about the traps of forgetting to delete the dynamic array with operator delete[] and then got confused themselves when they tried to help you along; it doesn't make much sense to implement a dynamic array as a plain class since it bakes in the element type.
The array memory allocated for vectors is released when the vector goes out of scope, in case the vector is declared on the stack (the backing array will be on the heap).
void foo() {
vector<int> v;
// ... method body
// backing array will be freed here
}
It says here: "Internally, vectors use a dynamically allocated array to store their elements."
Underlying concept of vectors is dynamically allocated array.
http://www.cplusplus.com/reference/vector/vector/
Maybe it's that dynamic array you would go through the copy process to a new dynamic array whenever you want to resize, but you are able to control when it does that depending on your knowledge of the data going into the array.
Whereas a vector uses the same process, but a vector does not know if it will grow or not later, so it probably allocates extra storage for possible growth in size, therefore it COULD possibly consume more memory space than intended to manage itself compared to dynamic arrays.
So, I'd say the difference is to use a vector when managing it's size is not a big deal, where you would use a dynamic array when you would rather do the resizing yourself.
Arrays have to be deallocated explicitly if defined dynamically whereas vectors are automatically de-allocated from heap memory.
Size of array cannot be determined if dynamically allocated whereas Size of the vector can be determined in O(1) time.
3.When arrays are passed to a function, a separate parameter for size is also passed whereas in case of passing a vector to a function, there is no such need as vector maintains variables which keeps track of size of container at all times.
4.When we allocate array dynamically then after size is initialized we cannot change the size whereasin vector we can do it.
I am looking for a C++ data type similar to std::vector but without the overhead related to dynamic resizing. The size of the container will remain constant over its lifetime. I considered using boost::array, however, that is not appropriate because it requires the size of the array to be known at compile time, which is not the case in my situation.
Measure if the dynamic resizing has really any performance impact before using anything non-standard.
Tip: With vector.reserve there will never be any array-reallocation.
There's no overhead in reallocation if you don't reallocate std::vector. So either:
construct the std::vector with a known size ahead (std::vector x(100))
call reserve(n) after construction to make sure that at least n elements can be pushed into the vector before reallocation occurs.
The overhead induced by dynamic resizing capability of std::vector is virtually non-existent.
If you needed an array of compile-time size, looking for something more efficient than std::vector would indeed be a good idea in many cases.
But the difference between fixed run-time size and dynamic run-time size is negligible. std::vector is a perfect solution in this case.
I've used a template class based on ideas from STLSoft's auto_buffer (I cobbled together my own implementation from Matthew Wilson's Imperfect C++ book along with some ideas from the STLSoft implementation). It allocates the array by default on the stack (or embedded in the class object) if it's small enough (based on a template parameter you provide). If your runtime allocation is larger than that, the array storage comes from the heap.
http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html
So the nice thing about this class is that for smaller small sizes, the allocation is essentially a no-op.
If the size of the array is not known at compile time, then the only option in C++ is a dynamically-allocated array. You can use a std::vector to guarantee RAII. As others have said, the fact that std::vectors can be resized doesn't mean that you have to resize them. Create the std::vector with the correct size, and then don't call anything that would resize it.