Values changing after adding object pointer to vector - c++

Let's say I have a struct "A" with four members there. The four members are named:
one
two
three
four
I also have a struct "B" with five members there. Four of the five members come from struct A.
Then I have a vector with struct B pointers. I add every created struct B to this vector.
This looks like this:
std :: vector <B *> vec;
for (A& a : input.buffer())
{
B b =
{
a.one, a.two, a.three, a.four, random value
};
vec.push_back (& ​​b);
}
function_which_needs_a_const_pointer_to_the_first_element_and_size_of_vector (vec.front (), vec.size ());
Now I have used a number of std :: cout at different points in the code.
I print the following values:
a.one = 1304505
b.one (just before the push_back) = 1304505
vec [0] -> one (after the push_back) = 24050434
So as you can see I am troubled by values ​​that change after adding to the vector, as a result of which the rest of the code can no longer function correctly.
Does anyone have any idea how I can solve this? I probably do something stupid.
I tried google now for two days, but nothing seemed to help.
Thanks to some of your comments I know now that there are dangling pointers. If I make it a vector of shared pointers instead of raw pointers, I will have a invalid conversion from shared pointer to const raw pointer error.
So now, we know the issue. But what is the best way to fix it? Because I am not allowed to touch that const raw pointer in that function.
Before you all press the down vote button; None of you is still able to give me the correct solution.

The immediate cause of the problem is that your objects don't exist when you try to use them.
You should never store a pointer you acquire with & for later use.
The more fundamental source of the problem is that you have misunderstood the exercise.
The function you're not allowed to modify wants a pointer to the vector's first element, but vec.front() is not a pointer to the vector's first element - it is the vector's first element.
(This element happens to be a pointer, but it's not a pointer to the beginning of the vector).
You can get pointer to vec's first element with &vec[0] or vec.data() or &vec.front().
This is what you should pass to the function, and your vector's type should be vector<B>.
That is,
std::vector<B> vec;
for (A& a: input.buffer())
{
B b ={ a.one, a.two, a.three, a.four, random value };
vec.push_back(​b);
}
function_with_long_name(vec.data(), vec.size());

When you vec.push_back (& ​​b);, you are pushing a pointer to an object that is about to cease to exist. There isn't a B to point to when you vec[0]->one

You pass an address of local variable that becomes unavailable when going out of scope, that's why your vector will contain pointers to memory with no data available.

See comments in code.
std :: vector <B > vec; // just copy them all
for (A& a : input.buffer())
{
B b =
{
a.one, a.two, a.three, a.four, random value
};
vec.push_back (​​b); //not passing by reference anymore, just copy.
}
function_which_needs_a_const_pointer_to_the_first_element_and_size_of_vector (&vec.front (), vec.size ()); // Passing the reference of vec->front for the first element of the vector.

Related

C++ vector: push_back an array of int => Does array get copied?

I'm new to C++'s object lifetime, so bear with me.
I have a vector of dynamically allocated arrays of integers: std::vector<int*>
This page says "The content of val is copied (or moved) to the new element."
What I understand from this is that what I push into the array MAY be moved or copied, but when is it moved and when is it copied?
I suspect the valued is copied if it's of primitive types? E.g., int, char, etc?
And it's copied otherwise? Does that means my array would be "moved"?
===================
EDIT 1: what I'm trying to find out is that suppose I pass the vector into a function. In this function I allocate an array of integers and push it into the vector. Once the function returns and I'm back to the caller, can I still safely access the array that was just pushed into the vector?
EDIT 2: some suggested using vector<vector<int>>, so my question became, if I pass the "parent" vector into some function. In this function, I create the inner vector and push it into the outer vector. When I'm back to the caller, can I still safely access the new inner vector that was just pushed into the outer vector?
Something like this:
void foo()
{
vector<vector<int>> parentV;
addVect(parentV);
//Is is safe to access parentV[0][0] here?
}
void addVect(vector<vector<int>> &parentV)
{
vector<int> child;
child.push_back(1);
child.push_back(2);
parentV.push_back(child);
}
some suggested using vector>, so my question became, if I
pass the "parent" vector into some function. In this function, I
create the inner vector and push it into the outer vector. When I'm
back to the caller, can I still safely access the new inner vector
that was just pushed into the outer vector?
void foo()
{
vector<vector<int>> parentV;
addVect(parentV);
//Is the "child" vector still safe for access here?
}
void addVect(vector<vector<int>> &parentV)
{
vector<int> child;
child.push_back(1);
child.push_back(2);
parentV.push_back(child);
}
To answer:
Is the "child" vector still safe for access here?
No and yes.
No, not through the name child at least. child is local to addVect and thus foo won't know anything about it. It will be destroyed after addVect returns.
Yes, you can access it's values through parentV since they've been copied to parentV and you're passing parentV as reference.
auto copyOfChild = *parentV.rbegin(); //get the last vector since push_back adds to the end of the vector
or
auto copyOfChild = parentV[parentV.size() - 1]; //get the last vector since push_back adds to the end of the vector
The pointer stored in the vector may be moved, but the address it points to won't, which means your data never move. If you had the actual ints in the vector and then took an address to one of them, that pointer could be invalidated if the vector had to be re-allocated, but since only the pointer is stored in the vector, your actual ints in the arrays will never be relocated.
but when is it moved and when is it copied?
It is based on value type that you pass. For example std::vvector::push_back() has 2 overrides:
void push_back( const T& value );
void push_back( T&& value );
so if you pass a type that can bind to rvalue refence, then second method is called and object is moved. Otherwise first method is called and object is copied.
I suspect the valued is copied if it's of primitive types? E.g., int, char, etc?
No it is based on value type, not if type primitive etc.
For example:
std::vector<Foobar> vec;
Foobar f;
vec.push_back( Foobar() ); // temporary binds to rvalue, move
vec.push_back( f ); // value copied
vec.push_back( std::move( f ) ); // now f moved
Does that means my array would be "moved"?
No your array cannot be moved. Vector could only move a variable that passed to it. Your variable is a pointer, not array. For raw pointer move is the same as copying one pointer to another.

Vector of objects containing references or pointers

I store some objects in a vector. When I call a member function of such an object that uses a reference the program gets terminated (no error). I wrote the following code do run some tests. It seams like after adding elements, the reference in the first entry fails. Why is that and what can I do to avoid this issue? It's exactly the same behaviour when I use pointers instead of references.
#include <iostream>
#include <vector>
using namespace std;
class A{
public:
A(int i) : var(i), ref(var) {}
int get_var() {return var;}
int get_ref() {return ref;}
private:
int var;
int& ref;
};
int main ()
{
vector<A> v;
for(unsigned int i=0;i<=2 ;i++){
v.emplace_back(i+5);
cout<<"entry "<<i<<":"<<endl;
cout<<" var="<<v.at(i).get_var()<<endl;
cout<<" ref="<<v.at(i).get_ref()<<endl;
}
cout<<endl;
for(unsigned int i=0;i<=2 ;i++){
cout<<"entry "<<i<<":"<<endl;
cout<<" var="<<v.at(i).get_var()<<endl;
cout<<" ref="<<v.at(i).get_ref()<<endl;
}
return 0;
}
The output is:
entry 0:
var=5
ref=5
entry 1:
var=6
ref=6
entry 2:
var=7
ref=7
entry 0:
var=5
ref=0 /////////////here it happens!
entry 1:
var=6
ref=6
entry 2:
var=7
ref=7
v has 3 entries
It's because your calls to emplace_back are causing the vector to resize. In order to do this, the vector may or may not have to move the entire vector to a different place in memory. Your "ref" is still referencing the old memory location.
Whether or not this actually happens is somewhat implementation dependent; compilers are free to reserve extra memory for the vector so they don't have to reallocate every single time you add something to the back.
It's mentioned in the standard documentation for emplace_back:
Iterator validity
If a reallocation happens, all iterators, pointers
and references related to this container are invalidated. Otherwise,
only the end iterator is invalidated, and all other iterators,
pointers and references to elements are guaranteed to keep referring
to the same elements they were referring to before the call.
To avoid the problem you could either (as JAB suggested in the comments) create the reference on the fly instead of storing it as a member variable:
int& get_ref() {return var;}
... although I would much rather use a smart pointer instead of this sort of thing.
Or, as RnMss suggested, implement the copy constructor so that it references the new location whenever the object is copied by vector:
A(A const& other) : ref(var) {
*this = other;
}
Okay, so here is what's happening. It really helps to understand your objects in terms of memory location, and remember that vector is allowed to move objects around in memory.
v.emplace_back(5)
You create an A-object in the vector. This object now resides in a block of memory ranging from 0x1234 to 0x123C. Member variable var sits at 0x1234 and member variable ref sits at 0x1238. For this object, the value of var is 0x0005 and the value of ref is 0x1234.
While adding elements to the vector, the vector runs out of space during the second insert. So, it resizes and moves the current elements (which at this moment is just the first element) from location 0x1234 to location 0x2000. This means the member elements also moved, so var is now located at address 0x2000 and ref is now located at 0x2004. But their values were copied, so the value of var is still 0x0005 and the value of ref is still 0x1234.
ref is pointing at an invalid location (but var still contains the right value!). Trying to access the memory ref now points to undefined behavior and generally bad.
Something like this would be a much more typical approach to providing reference access to a member attribute:
int & get_ref() {return var;}
Having references as member attributes isn't wrong in and of itself, but if you are storing a reference to an object, you have to make sure that that object doesn't move.

keeping track of vector elements addresses

I want to know if there is a way to keep track of addresses of elements in a vector.
I like to use vector of solid elements like std::vector<MyObject> vec because:
std::vector do all the allocation / deallocation stuff for me
it also ensures me that my elements are stored in contiguous memory
I can get benefits of all code that work with vectors (e.g. <algorithm>)
This is exactly what I want. The problem arises when I want to store the address / reference of elements of my vector in other objects. In fact, the problem really arises when std::vector need to reallocate memory.
I tried to find alternatives to my problem:
Use vector of pointers / smart pointers : No, the pointers will be allocated contiguously but not the elements
Use vector of pointers / smart pointers and write my own operator new/new[] for MyObject : Humm, that seems better but no. By using a vector to allocate my elements I can say : "those particular set (I do not refer here to std::set) of elements must be allocated contiguously, not all". In fact I may want to have other set of elements that should be allocated contiguously because of the way I want to use them and using a vector to do that is exactly what (I think) I need. Thats also implies that I'm doing the job I want the vector to do.
Why not using boost multi-index? : In some ways that will do what I want because I want to store pointers/smartpointers of my vector elements in other containers. But no again because I really want to store reference/pointer/smartpointer of my vector's elements inside other objects, not just other containers.
What I would loved to have is a vector that can give me a pointer object that will allways point the the address of the desired element and I will use it like that :
std::vector<MyObject> vec;
// insert some elements
...
// get a pointer object by index or by using an iterator
// does something like that exist?
std::vector<MyObject>::pointer ptr = vec.get_pointer_at(5);
// do what I want on the vector except removing the element
...
// use my pointer whatever reallocations occurred or not
ptr->doSomething();
That sounds like an iterator that will never be invalidated except the fact I don't need/want to perform arithmetic on it (+x, -x, ++, --).
So, can someone leads me to the way to achieve what I want or explain me why/where I'm wrong wanting to do this? Please accept my apologize for my lack of knowledge in STL if there is a well known solution that I missed / or if this question has already be answered.
Edit:
I think that if I have to code such kind of pointer, that means that I'm wanting something useless or I'm wrong somewhere (unless someone should have already wrote a template for that) . So I'm more looking to a validated C++ idiom to get rid of this problem.
Although std::vector does not give you such pointer, there is no reason why you cannot make one yourself. All it takes is a class that keeps a reference to the std::vector object and the index, and overloads the prefix operator * and the infix operator -> (you need four overloads - const and non-const for each operator).
You would use this pointer like this:
std::vector<int> vect = {2, 4, 6, 8, 10, 12, 14, 16};
vect_ptr<int> ptr(vect, 5); // <<== You need to implement this
*ptr = 123;
cout << *ptr << endl;
The implementation of these overloads would grab the std::vector's begin() iterator, and return the result of calling vect.at(index). This would look like a pointer from the outside, but the object to which it points would change as the content of the std::vector gets resized.
As far as I know, there is nothing in the standard library nor in Boost to address your problem. A solution would be to implement your own kind of element pointer:
template<typename T>
class vector_element
{
public:
vector_element( std::vector<T>& v, std::size_t i )
: m_container( v ), m_element_index(i)
{ }
T& operator*() { return m_container[m_element_index]; }
T* operator->() { return &m_container[m_element_index]; }
private:
std::vector<T>& m_container;
std::size_t m_element_index;
};

issues related to the copy of vector with pointer item

I want to ask whether there are some problems with the copy for the vector of pointer items. Do I need to strcpy or memcpy because there may be depth copy problem?
For instance:
Class B;
Class A
{
....
private:
std::vector<B*> bvec;
public:
void setB(std::vector<B*>& value)
{
this->bvec = value;
}
};
void main()
{
....
std::vector<const B*> value; // and already has values
A a;
a.setB(value);
}
This example only assign the value to the class variable bvec inside A class. Do I need to use memcpy since I found that std::vector bvec; has pointer items? I am confused with the depth copy in C++, could you make me clear about that? Thank you.
Think about this, if you remove and delete an item from the vector value after you call setB, then the vector in A will have a pointer that is no longer valid.
So either you need to do a "deep copy", have guarantees that the above scenario will never happen, or use shared smart pointers like std::shared_ptr instead of raw pointers. If you need pointers, I would recommend the last.
There is another alternative, and that is to store the vector in A as a reference to the real vector. However, this has other problems, like the real vector needs to be valid through the lifetime of the object. But here too you can use smart pointers, and allocate the vector dynamically.
It is unlikely you need strcpy or memcpy to solve your problem. However, I'm not sure what your problem is.
I will try to explain copying as it relates to std::vector.
When you assign bvev to value in setB you are making a deep copy. This means all of the elements in the vector are copied from value to bvec. If you have a vector of objects, each object is copied. If you have a vector of pointers, each pointer is copied.
Another option is to simply copy the pointer to the vector if you wish to reference the elements later on. Just be careful to manage the lifetimes properly!
I hope that helps!
You probably want to define your copy constructor for class A to ensure the problem your asking about is handled correctly (though not by using memcpy or strcpy). Always follow the rule of three here. I'm pretty sure with std::vector your good, but if not, then use a for loop instead of memcpy

Returning a pointer to a vector element in c++

I have a vector of myObjects in global scope.
I have a method which uses a std::vector<myObject>::const_iterator to traverse the vector, and doing some comparisons to find a specific element.
Once I have found the required element, I want to be able to return a pointer to it (the vector exists in global scope).
If I return &iterator, am I returning the address of the iterator or the address of what the iterator is pointing to?
Do I need to cast the const_iterator back to a myObject, then return the address of that?
Return the address of the thing pointed to by the iterator:
&(*iterator)
Edit: To clear up some confusion:
vector <int> vec; // a global vector of ints
void f() {
vec.push_back( 1 ); // add to the global vector
vector <int>::iterator it = vec.begin();
* it = 2; // change what was 1 to 2
int * p = &(*it); // get pointer to first element
* p = 3; // change what was 2 to 3
}
No need for vectors of pointers or dynamic allocation.
Returning &iterator will return the address of the iterator. If you want to return a way of referring to the element return the iterator itself.
Beware that you do not need the vector to be a global in order to return the iterator/pointer, but that operations in the vector can invalidate the iterator. Adding elements to the vector, for example, can move the vector elements to a different position if the new size() is greater than the reserved memory. Deletion of an element before the given item from the vector will make the iterator refer to a different element.
In both cases, depending on the STL implementation it can be hard to debug with just random errors happening each so often.
EDIT after comment: 'yes, I didn't want to return the iterator a) because its const, and b) surely it is only a local, temporary iterator? – Krakkos'
Iterators are not more or less local or temporary than any other variable and they are copyable. You can return it and the compiler will make the copy for you as it will with the pointer.
Now with the const-ness. If the caller wants to perform modifications through the returned element (whether pointer or iterator) then you should use a non-const iterator. (Just remove the 'const_' from the definition of the iterator).
You can use the data function of the vector:
Returns a pointer to the first element in the vector.
If don't want the pointer to the first element, but by index, then you can try, for example:
//the index to the element that you want to receive its pointer:
int i = n; //(n is whatever integer you want)
std::vector<myObject> vec;
myObject* ptr_to_first = vec.data();
//or
std::vector<myObject>* vec;
myObject* ptr_to_first = vec->data();
//then
myObject element = ptr_to_first[i]; //element at index i
myObject* ptr_to_element = &element;
It is not a good idea to return iterators. Iterators become invalid when modifications to the vector (inversion\deletion ) happens. Also, the iterator is a local object created on stack and hence returning the address of the same is not at all safe. I'd suggest you to work with myObject rather than vector iterators.
EDIT:
If the object is lightweight then its better you return the object itself. Otheriwise return pointers to myObject stored in the vector.
As long as your vector remains in global scope you can return:
&(*iterator)
I'll caution you that this is pretty dangerous in general. If your vector is ever moved out of global scope and is destructed, any pointers to myObject become invalid. If you're writing these functions as part of a larger project, returning a non-const pointer could lead someone to delete the return value. This will have undefined, and catastrophic, effects on the application.
I'd rewrite this as:
myObject myFunction(const vector<myObject>& objects)
{
// find the object in question and return a copy
return *iterator;
}
If you need to modify the returned myObject, store your values as pointers and allocate them on the heap:
myObject* myFunction(const vector<myObject*>& objects)
{
return *iterator;
}
That way you have control over when they're destructed.
Something like this will break your app:
g_vector<tmpClass> myVector;
tmpClass t;
t.i = 30;
myVector.push_back(t);
// my function returns a pointer to a value in myVector
std::auto_ptr<tmpClass> t2(myFunction());
Say, you have the following:
std::vector<myObject>::const_iterator first = vObj.begin();
Then the first object in the vector is: *first. To get the address, use: &(*first).
However, in keeping with the STL design, I'd suggest return an iterator instead if you plan to pass it around later on to STL algorithms.
You are storing the copies of the myObject in the vector. So I believe the copying the instance of myObject is not a costly operation. Then I think the safest would be return a copy of the myObject from your function.
Refer to dirkgently's and anon's answers, you can call the front function instead of begin function, so you do not have to write the *, but only the &.
Code Example:
vector<myObject> vec; //You have a vector of your objects
myObject first = vec.front(); //returns reference, not iterator, to the first object in the vector so you had only to write the data type in the generic of your vector, i.e. myObject, and not all the iterator stuff and the vector again and :: of course
myObject* pointer_to_first_object = &first; //* between & and first is not there anymore, first is already the first object, not iterator to it.
I'm not sure if returning the address of the thing pointed by the iterator is needed.
All you need is the pointer itself. You will see STL's iterator class itself implementing the use of _Ptr for this purpose. So, just do:
return iterator._Ptr;