Assuming I have this program below
The size of the array is 3 and basically when deleting it and then try to print the size again , I still get the value 3 .
Why is that ?
#include <vector>
#include <iostream>
int main(){
std::vector<int*> v;
v.push_back(new int{1});
v.push_back(new int{2});
v.push_back(new int{3});
std::cout << v.size() << '\n';
for (auto iptr : v){
delete iptr;
}
std::cout << v.size() << '\n';
return 0;
}
Because you deleted whatever was pointed by the pointer
vector<CPerson *> Persons;
As far as the vector is concerned, it still has 3 pointers pointing somewhere.Beware, you are not permitted to dereference them pointers, otherwise you will invoke undefined behavior).
You have a vector of pointers. Using delete on a pointer in that vector will delete the thing the pointer is pointing at. It does not remove the pointer itself from the vector, and so does not change the size of the vector. Why should it? How could it?
Here the code you were looking for (I guess):
for (int i = 0; i < Persons.size(); i++)
{
CPerson *Student = Persons[i];
if (Student)
{
Persons.erase(Persons.begin() + i);
delete Student;
i--;
}
}
Note:
vector::erase is (one way) to remove items from a vector.
The cast is unnecessary, because your base class has a virtual destructor.
Erasing items from a vector while you are iterating through it is tricky because the size of the vector changes when you erase an item and all the later items in the vector move down one place, that why I have i-- to compensate, without that you will at least skip items and at worst iterate off the end of the vector.
When you delete the pointers that are in the vector, it just deletes the memory that you assigned to them with new, it doesn't do anything about the fact that you have a pointer, there for you are cleaning up memory that is outside of the vector, the vector will clean it self up at the end of the scope. (In this case, the end of the function.) Just remember, the vector doesn't clean up your new memory, you have to clean that up.
I would like to loop through elements of a vector in C++.
I am very new at this so I don't understand the details very well.
For example:
for (elements in vector) {
if () {
check something
else {
//else add another element to the vector
vectorname.push_back(n)
}
}
Its the for (vector elements) that I am having trouble with.
You'd normally use what's called a range-based for loop for this:
for (auto element : your_vector)
if (condition(element))
// whatever
else
your_vector.push_back(something);
But note: modifying a vector in the middle of iteration is generally a poor idea. And if your basic notion is to add the element if it's not already present, you may want to look up std::set, std::map, std::unordered_set or std::unordered_map instead.
In order to do this properly (and safely), you need to understand how std::vector works.
vector capatity
You may know that a vector works much like an array with "infinite" size. Meaning, it can hold as many elements as you want, as long as you have enough memory to hold them. But how does it do that?
A vector has an internal buffer (think of it like an array allocated with new) that may be the same size as the elements you're storing, but generally it's larger. It uses the extra space in the buffer to insert any new elements that you want to insert when you use push_back().
The amount of elements the vector has is known as its size, and the amount of elements it can hold is known as its capacity. You can query those via the size() and capacity() member functions.
However, this extra space must end at some point. That's when the magic happens: When the vector notices it doesn't have enough memory to hold more elements, it allocates a new buffer, larger1 than the previous one, and copies all elements to it. The important thing to notice here is that the new buffer will have a different address. As we continue with this explanation, keep this in mind.
iterators
Now, we need to talk about iterators. I don't know how much of C++ you have studied yet, but think of an old plain array:
int my_array[5] = {1,2,3,4,5};
you can take the address of the first element by doing:
int* begin = my_array;
and you can take the address of the end of the array (more specifically, one past the last element) by doing:
int* end = begin + sizeof(my_array)/sizeof(int);
if you have these addresses, one way to iterate the array and print all elements would be:
for (int* it = begin; it < end; ++it) {
std::cout << *it;
}
An iterator works much like a pointer. If you increment it (like we do with the pointer using ++it above), it will point to the next element. If you dereference it (again, like we do with the pointer using *it above), it will return the element it is pointing to.
std::vector provides us with two member functions, begin() and end(), that return iterators analogous to our begin and end pointers above. This is what you need to keep in mind from this section: Internally, these iterators have pointers that point to the elements in the vector's internal buffer.
a simpler way to iterate
Theoretically, you can use std::vector::begin() and std::vector::end to iterate a vector like this:
std::vector<int> v{1,2,3,4,5};
for (std::vector<int>::iterator it = v.begin; it != v.end(); ++it) {
std::cout << *it;
}
Note that, apart from the ugly type of it, this is exactly the same as our pointer example. C++ introduced the keyword auto, that lets us get rid of these ugly types, when we don't really need to know them:
std::vector<int> v{1,2,3,4,5};
for (auto it = v.begin; it != v.end(); ++it) {
std::cout << *it;
}
This works exactly the same (in fact, it has the exact same type), but now we don't need to type (or read) that uglyness.
But, there's an even better way. C++ has also introduced range-based for:
std::vector<int> v{1,2,3,4,5};
for (auto it : v) {
std::cout << it;
}
the range-based for construct does several things for you:
It calls v.begin() and v.end()2 to get the upper and lower bounds of the range we're going to iterate;
Keeps an internal iterator (let's call it i), and calls ++i on every step of the loop;
Dereferences the iterator (by calling *i) and stores it in the it variable for us. This means we do not need to dereference it ourselves (note how the std::cout << it line looks different from the other examples)
putting it all together
Let's do a small exercise. We're going to iterate a vector of numbers, and, for each odd number, we are going to insert a new elements equal to 2*n.
This is the naive way that we could probably think at first:
std::vector<int> v{1,2,3,4,5};
for (int i : v) {
if (i%2==1) {
v.push_back(i*2);
}
}
Of course, this is wrong! Vector v will start with a capacity of 5. This means that, when we try using push_back for the first time, it will allocate a new buffer.
If the buffer was reallocated, its address has changed. Then, what happens to the internal pointer that the range-based for is using to iterate the vector? It no longer points to the buffer!
This it what we call a reference invalidation. Look at the reference for std::vector::push_back. At the very beginning, it says:
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.
Once the range-based for tries to increment and dereference the now invalid pointer, bad things will happen.
There are several ways to avoid this. For instance, in this particular algorithm, I know that we can never insert more than n new elements. This means that the size of the vector can never go past 2n after the loop has ended. With this knowledge in hand, I can increase the vector's capacity beforehand:
std::vector<int> v{1,2,3,4,5};
v.reserve(v.size()*2); // Increases the capacity of the vector to at least size*2.
// The code bellow now works properly!
for (int i : v) {
if (i%2==1) {
v.push_back(i*2);
}
}
If for some reason I don't know this information for a particular algorithm, I can use a separate vector to store the new elements, and then add them to our vector at the end:
std::vector<int> v{1,2,3,4,5};
std::vector<int> doubles;
for (int i : v) {
if (i%2==1) {
doubles.push_back(i*2);
}
}
// Reserving space is not necessary because the vector will allocate
// memory if it needs to anyway, but this does makes things faster
v.reserve(v.size() + doubles.size());
// There's a standard algorithm (std::copy), that, when used in conjunction with
// std::back_inserter, does this for us, but I find that the code bellow is more
// readable.
for (int i : doubles) {
v.push_back(i);
}
Finally, there's the old plain for, using an int to iterate. The iterator cannot be invalidated because it holds an index, instead of a pointer to the internal buffer:
std::vector<int> v{1,2,3,4,5};
for (int i = 0; i < v.size(); ++i) {
if (v[i]%2==1) {
doubles.push_back(v[i]*2);
}
}
Hopefully by now, you understand the advantages and drawbacks of each method. Happy studies!
1 How much larger depends on the implementation. Generally, implementations choose to allocate a new buffer of twice the size of the current buffer.
2 This is a small lie. The whole story is a bit more complicated: It actually tries to call begin(v) and end(v). Because vector is in the std namespace, it ends up calling std::begin and std::end, which, in turn, call v.begin() and v.end(). All of this machinery is there to ensure that the range-based for works not only with standard containers, but also with anything with a proper implementation for begin and end. That includes, for instance, regular plain arrays.
Here is the quick code snippet using iterators to iterate the vector-
#include<iostream>
#include<iterator> // for iterators to include
#include<vector> // for vectors to include
using namespace std;
int main()
{
vector<int> ar = { 1, 2, 3, 4, 5 };
// Declaring iterator to a vector
vector<int>::iterator ptr;
// Displaying vector elements using begin() and end()
cout << "The vector elements are : ";
for (ptr = ar.begin(); ptr < ar.end(); ptr++)
cout << *ptr << " ";
return 0;
}
Article to read more - Iterate through a C++ Vector using a 'for' loop
.
Hope it will help.
Try this,
#include<iostream>
#include<vector>
int main()
{
std::vector<int> vec(5);
for(int i=0;i<10;i++)
{
if(i<vec.size())
vec[i]=i;
else
vec.push_back(i);
}
for(int i=0;i<vec.size();i++)
std::cout<<vec[i];
return 0;
}
Output:
0123456789
Process returned 0 (0x0) execution time : 0.328 s
Press any key to continue.
How do I [dynamically?] declare an array with an 'i' number of elements?
By using a container of the standard-library instead, most commonly std::vector<>.
Other solutions contain manual allocation and deallocation of memory and are probably not worth the effort.
You could use std::vector<T>. It works like
std::vector<int> a;
a.push_back(2); // add 2 to the array
a.push_back(4);
You could go on and on, and you won't need to worry about memory allocation issues.
You have to use pointers.
Example:
float *ptrarray = new float [10];
Basically, type * pointername = new type [i];
And don't forget to clean your memory:
delete [] ptrarray;
Or it will be reserved until the program ends.
Create a Dynamically Sized Array
std::size_t N = 10;
SomeType *a = new SomeType[N];
for (auto i=0; i<N; ++i) {
std::cout << a[i] << std::endl;
}
delete [] a;
A C++ array is a pointer to a contiguous chunk of memory containing a specific type. This snippet allocates space for an array of 10 SomeType instances, constructs the array which initializes each object using the default constructor, iterates over the array, prints out each element, and then deallocates the memory by calling delete [].
Key Points:
you are required to call delete [] to deallocate the array. The array form is required to ensure that the destructor is called on each object.
after allocation, there is no way to recover the size of the array.
you can iterate over the array by index (or pointer)
This is not the way to do what you want, keep reading.
Using a vector
std::size_t N = 10;
std::vector<SomeType> v(10);
for (auto iter=v.begin(); iter!=v.end(); ++iter) {
std::cout << *iter << std::endl;
}
This snippet uses std::vector which manages a contiguous block of memory for you. Note the usage of an iterator to walk over the vector instead of using indexing. Vectors do support direct indexing so the for loop used in the previous example would work here as well.
for (auto i=0; i<v.size(); ++i) {
std::cout << v[i] << std::endl;
}
Using an iterator is the best practice and idiomatic though using a for loop may not be but I digress.
Key Points:
memory management is automatic in the case of a vector
you can append using push_back
a vector knows how many elements are in it -- call v.size() to get the number of elements
iteration is performed using the iterators returned from v.begin() and v.end()
Just use std::vector. If you need raw access to the underlying pointer, then use &v[0] or v.data() but don't do that unless you need to. Also, don't use std::auto_ptr for arrays. You will be tempted to but don't do it.
I ran into this problem when I tried to write out an new algorithm to reorder elements in std::vector. The basic idea is that I have std::list of pointters pointing into std::vector in such way that *list.begin() == vector[0], *(++list.begin()) == vector[1] and so on.
However, any modifications on list's element positions breaks the mapping. (Including appended pointers) When the mapping is broken the list's elements can be in random order but they point still into correct elements on vector. The task would be to reorder the elements in vector to correct the mapping.
Simplest method to do it (How I have done it now):
create new empty std::vector and resize it to equal size of the old vector.
iterate through the list and read elements from the old vector and write them into new vector. Set the pointer to point into new vector's element.
swap vectors and release the old vector.
Sadly the method is only useful when I need more capacity on the vector. It's inefficient when the current vector holding the elements has enough capacity to store all incoming elements. Appended pointers on the list will point into diffrent vector's storgate. The simple method works for this because it only reads from the pointers.
So I would want to reorder the vector "in place" using constant amount of memory. Any pointer that was not pointing into current vector's storgate are moved to point into current vector's storgate. Elements are simple structures. (PODs)
I'll try post an example code when I have time..
What should I do to achieve this? I have the basic idea done, but I'm not sure if it is even possible to do the reordering with constant amount of memory.
PS: I'm sorry for the (possibly) bad grammar and typos in the post. I hope it's still readable. :)
First off, why do you have a list of pointers? You might as well keep indices into the vector, which you can compute as std::distance(&v[0], *list_iter). So, let's build a vector of indices first, but you can easily adapt that to use your list directly:
std::vector<T> v; // your data
std::list<T*> perm_list; // your given permutation list
std::vector<size_t> perms;
perms.reserve(v.size());
for (std::list<T*>::const_iterator it = perm_list.begin(), end = perm_list.end(); it != end; ++it)
{
perms.push_back(std::distance(&v[0], *it));
}
(There's probably a way to use std::transform and std::bind, or lambdas, to do this in one line.)
Now to do the work. We simply use the cycle-decomposition of the permutation, and we modify the perms vector as we go along:
std::set<size_t> done;
for (size_t i = 0; i < perms.size(); while(done.count(++i)) {})
{
T tmp1 = v[i];
for (size_t j = perms[i]; j != i; j = perms[j])
{
T tmp2 = v[j];
v[j] = tmp1;
tmp1 = tmp2;
done.insert(j);
}
v[i] = tmp1;
}
I'm using the auxiliary set done to track which indices have already been permuted. In C++0x you would add std::move everywhere to make this work with movable containers.
I have some vectors of class A objects:
std::vector<A> *V1;
std::vector<A> *V2;
etc
there is a function with a vector of pointers of A:
std::vector<A *> *arranged;
what I need to do is put the vectors from V1, V2 etc inside arranged without destroying them in the end, so I thought that a vector of pointers to those objects... is this possible?
if yes, can you give me an example of a iteration with variable V1 and add pointers of those objects into arranged?
imagine that you, temporarly, need to sort 3 vectors of objects into one vector but you don't want to mess up the memory of the 3 vectors.
ty,
Joe
You could write your own comparator. In this case, the comparator would work on A*. A simple example using int type:
void fun(vector<int*>* vec)
{
/////////
}
bool comp(int* lhs, int* rhs)
{
return *lhs < *rhs;
}
int main()
{
vector<int> first, second;
vector<int*> vec;
for(vector<int>::size_type i = 0; i < first.size(); ++i)
vec.push_back(&first[i]);
for(vector<int>::size_type i = 0; i < second.size(); ++i)
vec.push_back(&second[i]);
// write your own comparator! provided above: comp
sort(vec.begin(), vec.end(), comp);
fun(&vec);
return 0;
}
If I understand you correctly - you've several vectors containing some object type (A), and you want to create a new vector containing the composition of all members of the other vectors w/o actually copying the objects around, or otherwise disturbing their owning-vectors in any way?
First: does the new composite vector's life definitely exist such that none of its source-vectors will change? That is: you cannot just have raw pointers into the source-vectors from your composite vector if those pointers will be invalidated within the lifetime of your composite.
If the answer to that is anything other than "definitely, pointers will remain valid" then you need to consider using shared pointers, or something similar, such that altering the source-vectors will not leave your composite vector in an invalid state (i.e. not leave it pointing to random memory).
Assuming that the source-vectors will remain unchanged in terms of their own contents for the life span of your composite, then the simple answer is "Yes"
vector<A> source1;
vector<A> source2;
vector<A> source3;
vector<const A*> composite; // this is a sorted vector of the above vectors' contents (by pointer)
For the composite vector, you would need to put the contents (by copy) of source1-3 into it, and then sort it (or you could use a sorted container, and sort as you insert the elements). You'll need to define your own sorting operator, one that dereferences the pointers and applies whatever sort-algorithm on the target objects themselves.
Does that help you?