Using a pointer to an object stored in a vector... c++ - c++

I have a vector of myObjects in global scope.
std::vector<myObject>
A method is passed a pointer to one of the elements in the vector.
Can this method increment the pointer, to get to the next element,
myObject* pmObj;
++pmObj; // the next element ??
or should it be passed an std::Vector<myObject>::iterator and increment that instead?
Assume for now that the vector will not get changed in the meantime.

Yes - the standard guarantees in a technical correction that the storage for a vector is contiguous, so incrementing pointers into a vector will work.

Yes, this will work as expected since std::vector is mandated to use contiguous storage by the Standard. I would suggest passing in a pair of iterators if you are working with a range of objects. This is pretty much the standard idiom as employed by the STL. This will make your code a little safer as well since you have an explicit endpoint for iteration instead of relying on a count or something like that.

If the vector is not reallocated and you're sure not to get out of vector's bounds then you can use this approach. Incrementing pointers is legal and while you have space to move to the next element you can do so by incrementing the pointer since the vector's buffer is a single block of memory.

Related

With a 2D vector, does calling clear() on the 1st level clear all the memory associated with that vector?

I have a 2D vector declared as such:
vector<vector<uint16_t>> vector;
After this is used and I need to clear all memory associated with it, even the elements in the [][X] dimension, can I simply do:
vector.clear();
Or do I have to go through each of the vectors inside and call .clear() on them, before finally calling it on the main vector? If that is the case, what would be a clean solution for that?
Since a vector neatly destructs its elements and deallocates the used memory when itself gets destructed, and v.clear() also destructs the elements in the vector, calling v.clear() is a perfectly valid way to delete an entire 2D vector.
Note that if you want also the memory for v itself cleaned up you need to call v.shrink_to_fit() after v.clear().
With a 2D vector, does calling clear() on the 1st level clear all the memory associated
with that vector?
Yes, clear erases all elements from the container.
Quoting from here,
std::vector<T,Allocator>::clear
After this call, size() returns zero.
Invalidates any references, pointers, or iterators referring to contained elements. Any
past-the-end iterators are also invalidated.
But this does not affect allocation/deallocation of internal storage in any way whatsoever. So, if you meant to ask,
With a 2D vector, does calling clear() on the 1st level FREE all the memory associated
with that vector?
No. As per standard,
Leaves the capacity() of the vector unchanged (note: the standard's restriction on the
changes to capacity is in the specification of vector::reserve, see 1)
So, if you wish to free up memory, either go for shrink_to_fit() or better swap contents with an empty vector. This is what most but not all implementations do.
v.swap(std::vector<T>());
v.swap(std::vector<std::vector<T>>()); // if vector of vectors

Using delete [] on an object in an array

How would I use delete on a specific class object in an array to ONLY delete that object and not the whole array?
This object will be no matter what be at the end of the array, so moving the other objects in the array doesn't matter also
EDIT:
To make it more clearer, I just want to free up the last element of the array for later use.
You should use std::vector instead of a regular array if you need to do this. With std::vector, removing and destroying the final element is done via the pop_back method.
If you absolutely must use a regular array, and must destroy one object inside the array right now, you can placement-destroy that object and then construct a new one in its place. If you aren't sure what this means or how to do it, you probably should be using std::vector instead.
If you want to copy the last element of the array to somewhere else, simply do that and then ignore the last element. You cannot remove it. Usually you have a counter variable somewhere that holds the amount of elements currently in the array. So when you "remove" the last element, simply decrement that counter by 1.
FYI, std::vector works exactly the same way. (And you should be using std::vector to begin with anyway.)
An array allocated with the new[] directive can only be released with the delete[] directive. Any other attempt to release part of or the entire array (free, delete etc.) is undefined behaviour.
If you want to be able to free a specific element in the array then you are better off looking into using an stl container such as std::vector, std::list, std::set, std::map etc. Each has different properties and is appropriate for a different task, but all support fast deletion of elements (except vector which only supports "fast" delteion of the last element but since that is exactly what you wanted then its a good option) and in fact "hide" the allocation of elements for you.
If the array is like
object* array = new object[n];
Then you cannot delete an element of it. You can move the elements by using memcpy(), but not change the size of the array.
Using new or delete on an array item will result in heap corruption in the majority of cases. As suggested, you should use std::vector.
If the array is an array of pointers to objects, then you can delete a pointed object but you cannot delete the pointer itself (see first part of this answer).
EDIT: a comment from the author of the question specify that he wants to remove the last element of a pointer array.
You can set the last pointer to 0 and check:
pointers[size - 1] = 0;
// later, when using the array
if(pointers[i]) // do smth
Using std::vector will be more easy. Also, if you deletions are frequent enough, you should consider using std::list.

why not implement c++ std::vector::pop_front() by shifting the pointer to vector[0]?

Why can't pop_front() be implemented for C++ vectors by simply shifting the pointer contained in the vector's name one spot over? So in a vector containing an array foo, foo is a pointer to foo[0], so pop_front() would make the pointer foo = foo[1] and the bracket operator would just do the normal pointer math. Is this something to do with how C++ keeps track of the memory you're using for what when it allocates space for an array?
This is similar to other questions I've seen about why std::vector doesn't have a pop_front() function, I will admit, but i haven't anyone asking about why you can't shift the pointer.
The vector wouldn't be able to free its memory if it did this.
Generally, you want the overhead per vector object to be small. That means you only store three items: the pointer to the first element, the capacity, and the length.
In order to implement what you suggest, every vector ever (all of them) would need an additional member variable: the offset from the start pointer at which the zeroth element resides. Otherwise, the memory could not be freed, since the original handle to it would have been lost.
It's a tradeoff, but generally the memory consumption of an object which may have millions of instances is more valuable than the corner case of doing the absolute worst thing you can do performance-wise to the vector.
Because implementers want to optimize the size of a vector. They usually use 3 pointers, one for the beginning, one for the capacity (the allocated end) and one for the end.
Doing what you require adds another 4 bytes to every vector (and there are a lot of those in a c++ program) for very little benefit: the contract of vector is to be fast when pushing back new elements, removing and inserting are "unsual" operations and their performance matter less than the size of the class.
I started typing out an elaborate answer explaining how the memory is allocated and freed but after typing it all out I realized that memory issues alone don't justify why pop_front isn't there as other answers here suggested.
Having pop_front in a vector where the extra cost is another pointer is justifiable in most circumstances. The problem, in my opinion, is push_front. If the container has pop_front then it should also have push_front otherwise the container is not being consistent. push_front is definitely expensive for a vector container (unless you match your pushes with your pops which is not a good design). Without push_front the vector is really wasting memory if one does lots of pop_front operations with no push_front functionality.
Now the need for pop_front and push_front is there for a container that is similar to a vector (constant time random access) which is why there is deque.
You could, but it would complicate the implementation a bit, and add a pointer of overhead to the type's size (so it could track the actual allocation's address). Is that worth it? Sometimes. First consider other structures which may handle your usage better (maybe deque?).
You could do that, but vector is designed to be a simple container with constant time index lookups and push/pop from the end. Doing what you suggest would complicate the implementation as it would have to track the allocated beginning and the "current" beginning. Not to mention that you still couldn't guarantee constant time insertion at the front but you might get it sometimes.
If you need a container with constant time front and back insertion and removal, that's precisely what deque is for, there's no need to modify vector to handle it.
You can use std::deque instead of std::vector. It's a double-ended-queue with also the vector-like access members. It implements both front and back push/pop.
http://www.cplusplus.com/reference/stl/deque/
Another shortcoming of your suggestion is that you'll waste memory spaces as you can't make use of those on the left of the array after shifting. The more you execute pop_front(), the more you'll waste until the vector is destructed.

Constant reference std::vector

How can I have a reference to a specific element in a std::vector?
The easy way should be to store it as the index of the element (I am using a size_t variable).
The problem I have is the possibility of inserting an element before the current, making the stored value incorrect.
There isn't a very good way to keep track of a single element inside the vector by a pointer, reference, or index. In particular:
If you insert a new element into the vector, it may cause all outstanding references to the vector's elements to be invalidated if an internal reallocation occurs. Insertions can happen either by calling insert, reserve, push_back, or assign (plus perhaps a few others). This could cause the reference to refer to an invalid object, resulting in undefined behavior if the reference is used.
If you remove an element from the vector, then the reference may no longer point at the same element. Accessing the reference may result in you referring to the wrong object.
If you really must hold a reference to an element in a vector, one option would be to have the vector store (smart) pointers to objects instead of the objects themselves. That way, you can store a copy of that pointer elsewhere and no matter what happens in the vector, the pointer should still be valid. This is really the Fundamental Theorem of Software Engineering in practice - adding another layer of indirection can solve most problems.
The only reliable solution is to have your vector be a vector of pointers and just remember your pointer.
Otherwise you can't maintain a reference because, as you mentioned, the vector might move elements around.
Use a vector that contains auto pointers, i.e. std::vector<std::unique_ptr<YOUR_ELEMENT_TYPE>> if you are using c++0x.

Does std::vector change its address? How to avoid

Since vector elements are stored contiguously, I guess it may not have the same address after some push_back's , because the initial allocated space could not suffice.
I'm working on a code where I need a reference to an element in a vector, like:
int main(){
vector<int> v;
v.push_back(1);
int *ptr = &v[0];
for(int i=2; i<100; i++)
v.push_back(i);
cout << *ptr << endl; //?
return 0;
}
But it's not necessarily true that ptr contains a reference to v[0], right? How would be a good way to guarantee it?
My first idea would be to use a vector of pointers and dynamic allocation. I'm wondering if there's an easier way to do that?
PS.: Actually I'm using a vector of a class instead of int, but I think the issues are the same.
Don't use reserve to postpone this dangling pointer bug - as someone who got this same problem, shrugged, reserved 1000, then a few months later spent ages trying to figure out some weird memory bug (the vector capacity exceeded 1000), I can tell you this is not a robust solution.
You want to avoid taking the address of elements in a vector if at all possible precisely because of the unpredictable nature of reallocations. If you have to, use iterators instead of raw addresses, since checked STL implementations will tell you when they have become invalid, instead of randomly crashing.
The best solution is to change your container:
You could use std::list - it does not invalidate existing iterators when adding elements, and only the iterator to an erased element is invalidated when erasing
If you're using C++0x, std::vector<std::unique_ptr<T>> is an interesting solution
Alternatively, using pointers and new/delete isn't too bad - just don't forget to delete pointers before erasing them. It's not hard to get right this way, but you have to be pretty careful to not cause a memory leak by forgetting a delete. (Mark Ransom also points out: this is not exception safe, the entire vector contents is leaked if an exception causes the vector to be destroyed.)
Note that boost's ptr_vector cannot be used safely with some of the STL algorithms, which may be a problem for you.
You can increase the capacity of the underlying array used by the vector by calling its reserve member function:
v.reserve(100);
So long as you do not put more than 100 elements into the vector, ptr will point to the first element.
How would be a good way to guarantee it?
std::vector<T> is guaranteed to be continous, but the implementation is free to reallocate or free storage on operations altering the vector contents (vector iterators, pointers or references to elements become undefined as well).
You can achieve your desired result, however, by calling reserve. IIRC, the standard guarantees that no reallocations are done until the size of the vector is larger than its reserved capacity.
Generally, I'd be careful with it (you can quickly get trapped…). Better don't rely on std::vector<>::reserve and iterator persistence unless you really have to.
If you don't need your values stored contiguously, you can use std::deque instead of std::vector. It doesn't reallocate, but holds elements in several chunks of memory.
Another possibility possibility would be a purpose-built smart pointer that, instead of storing an address would store the address of the vector itself along with the the index of the item you care about. It would then put those together and get the address of the element only when you dereference it, something like this:
template <class T>
class vec_ptr {
std::vector<T> &v;
size_t index;
public:
vec_ptr(std::vector<T> &v, size_t index) : v(v), index(index) {}
T &operator*() { return v[index]; }
};
Then your int *ptr=&v[0]; would be replaced with something like: vec_ptr<int> ptr(v,0);
A couple of points: first of all, if you rearrange the items in your vector between the time you create the "pointer" and the time you dereference it, it will no longer refer to the original element, but to whatever element happens to be at the specified position. Second, this does no range checking, so (for example) attempting to use the 100th item in a vector that only contains 50 items will give undefined behavior.
As James McNellis and Alexander Gessler stated, reserve is a good way of pre-allocating memory. However, for completeness' sake, I'd like to add that for the pointers to remain valid, all insertion/removal operations must occur from the tail of the vector, otherwise item shifting will again invalidate your pointers.
Depending on your requirements and use case, you might want to take a look at Boost's Pointer Container Library.
In your case you could use boost::ptr_vector<yourClass>.
I came across this problem too and spent a whole day just to realize vector's address changed and the saved addresses became invalid. For my problem, my solution was that
save raw data in the vector and get relative indices
after the vector stopped growing, convert the indices to pointer addresses
I found the following works
pointers[i]=indices[i]+(size_t)&vector[0];
pointers[i]=&vector[ (size_t)indices[i] ];
However, I haven't figured out how to use vector.front() and I am not sure whether I should use
pointers[i]=indices[i]*sizeof(vector)+(size_t)&vector[0] . I think the reference way(2) should be very safe.