C++ Pass by value/reference - c++

I have the following code snippet:
vector<DEMData>* dems = new vector<DEMData>();
ConsumeXMLFile(dems);
if(!udp_open(2500))
{
}
I want the ConsumeXMLFile method to populate the vector with DEMData objects built from reading an XML file. When ConsumeXMLFile returns, the dems vector is empty. I think I'm running into a pass by value problem.

By the looks of this the ConsumeXMLFile takes a pointer to a vector so I doubt this is a pass by value problem.

Are you at any point reassigning the pointer that is passed into the function? In other words, does your function look anything like this:
void ConsumeXMLFile(vector<DEMData>* dems)
{
// ... some code ...
dems = new vector<DEMData>();
// ...more code...
}
This is a common mistake that I see beginning C++ programmers (and C programmers) make. What is going on here is that a pointer to the dems vector is being passed by value, which means that if you modify the pointed-to vector, that will affect the the vector possessed by the caller. However if you modify the pointer (which is passed by value) this will not affect the pointer possessed by the caller. After the re-assignment, the dems pointer in ConsumeXMLFile will point to a totally different vector than the dems pointer that the caller holds.
One of the things that makes me suspect that you might be doing this is that this is C++ and there's no clear reason why you would want to pass a pointer to the vector instead of a reference to the vector otherwise.

Related

C++ Vector pointer problems/Vector of pointers to a object in a vector

So, it seems that a lot of people new to C++ have problems with vectors, as their is a ton of questions about vector. I am not really new to C++ but I have never had this problem. Anyway, so my problem is with vector pointers. I am making a video game with a vector that holds the objects. It holds a reference to the objects so it can do collision response inside the collision function. To load the vector I used to do something like this:
Object a = Object(12, 135, 123, 124);
collision_rects.push_back(&a);
It worked perfectly like this, however I didn't want to type each individual object, so I made a function that read it from a text file, like this.
void get_from_file()
{
//Blah blah read numbers from file.
//then I would get the numbers and make a object from them.
Object a = Object(numbers from file);
collision_rects.push_back(&a);
}
But doing this didn't work! I fall through the floor! If I take the same data and load it the first way it works fine, but when I do it from a function in a text file it doesn't. I then realized that maybe it was because the Object went out of scope. So I tried making an object global then doing the same in the function, which worked. This is essentially the same as the first option but in a function. So I made two vectors, on the same scope so that the original object would not go out of scope like this.
std::vector<Object> objects;
void get_from_file()
{
//blah blah
objects[i] = Object(nums from file); //reading from numbers in a for loop
collision_rects.push_back(&objects[i]); //This throws weird
This didn't work either.(By the way, this is not even close to actual code, just a example of what the code does basically.
What am I doing wrong? Thanks.
EDIT
So I don't know if I explained it perfectly, but I don't think its the problem that its pointing to a deleted object. That certainly would make it not work, however it is also another reason I believe.
player->cHandler.objects.push_back(&uno);
player->cHandler.objects.push_back(&dos);
player->cHandler.objects.push_back(&tres);
player->cHandler.objects.push_back(&quatro);
player->cHandler.objects.push_back(&cinco);
player->cHandler.objects.push_back(&seis);
player->cHandler.objects.push_back(&a8);
player->cHandler.objects.push_back(&a9);
player->cHandler.objects.push_back(&a10);
player->cHandler.objects.push_back(&a11);
player->cHandler.objects.push_back(&a12);
player->cHandler.objects.push_back(&a13);
player->cHandler.objects.push_back(&a14);
player->cHandler.objects.push_back(&a15);
player->cHandler.objects.push_back(&a16);
player->cHandler.objects.push_back(&a17);
player->cHandler.objects.push_back(&a18);
player->cHandler.objects.push_back(&a19);
player->cHandler.objects.push_back(&a20);
Now this is my actual code that works.
However when I do it like this, it doesn't work.
objs.push_back(uno);
objs.push_back(dos);
objs.push_back(tres);
objs.push_back(quatro);
objs.push_back(cinco);
objs.push_back(seis);
objs.push_back(a8);
objs.push_back(a9);
objs.push_back(a10);
objs.push_back(a11);
objs.push_back(a12);
objs.push_back(a13);
objs.push_back(a14);
objs.push_back(a15);
objs.push_back(a16);
objs.push_back(a17);
objs.push_back(a18);
objs.push_back(a19);
objs.push_back(a20);
for (int i = 0; i < objs.size(); i++)
{
//player->cHandler.objects.push_back(&objs[i]);
}
This is not working, and I don't know why.
Your issue has nothing to do with std::vector. You only discovered the underlying problem by using vector, however you would have the very same problem if you returned a pointer to the object you created, or if you had a plain array and stored a pointer to the object in the array.
You're storing pointers to a local variable:
void get_from_file()
{
Object a = Object(numbers from file);
collision_rects.push_back(&a);
}
When the get_from_file() function returns, that a will be destroyed since it is a local object. Your collision_rects vector will thus have a pointer to a variable that no longer exists.
The same issue would have occurred with this code:
Object* get_from_file()
{
Object a = Object(numbers from file);
return &a; // returning pointer to local variable. Bad.
}
So the solution is to make sure that the object's lifetime exists outside the get_from_file function.
You can either store objects in your vector (a std::vector<Object>), or if it must be pointer, it should be a pointer to an object that has a lifetime beyond the get_from_file() function. That can be accomplished by allocating from the heap using new, or better yet, using a smart pointer type.
You're storing a pointer to the objects, but the objects are then being destroyed so you're left with a pointer to nothing.
One good option is to store the objects themselves in the vector rather than the pointers.
Alternatively you could allocate an object on the heap (using e.g. new Object(1, 2, 3)) and store that pointer (that way the object isn't destroyed until you want it to be). If you do that I would recommend storing a shared_ptr or unique_ptr - they do a lot of the work for you and make it easier to write correct code.
If it's ok for you that objects in your std::vector get destroyed when std::vector is destoyed, store them in std::vector<Object>, and use emplace_back to construct them directly in the vector, without the need of temporary local variable:
std::vector<Object> collision_rects;
collision_rects.emplace_back(nums from file);

C++ storing local variable into a vector prevents it from being destroyed when out of scope

I've encountered this piece of existing code, and being still new to C++, I don't understand why storing a local variable into a vector makes it still accessible later.
Here's the simplified flow of the code, where BackendCall is some class defined earlier:
void SaveBackendCall(BackendCall* backend_call,
vector<BackendCall>* logged_calls) {
logged_calls->push_back(*backend_call);
}
void AddNewCall(vector<BackendCall>* logged_calls) {
BackendCall backend_call; // The local variable in question.
SaveBackendCall(&backend_call, logged_calls);
}
vector<BackendCall> logged_calls;
AddNewCall(&logged_calls);
for (auto i = logged_calls->begin(); i != logged_calls->end(); ++i) {
i->access_stuff(); // This still works?
}
Wouldn't the local variable backend_call in AddNewCall() be destroyed after the function returns? Then I don't understand what is actually stored in logged_calls.
Would it make sense to convert the vector of BackendCall objects into a vector of unique_ptrs?
As the commenters have noted, vector<T>::push_back(someT) pushes a copy of someT onto the vector. It's true that by the time you get to your iteration loop, the original variable named backend_call has already departed for the great stack in the sky (which shall never overflow); or possibly it's been reincarnated as i (who knows? I don't want to debate religion here). But its memory lives on in the form of a facsimile inside logged_calls's buffer.
The vector is a vector of BackendCall objects. When adding objects to a vector, the copy constructor is called.
If you look at SaveBackendCall(), you will notice that it is dereferencing the pointer, which means it is passing in a reference to the object, not the pointer. (If the vector stored pointers, this would be dangerous code since what it is pointing to is going away when the stack goes out of scope.)
So what is happening here is:
AddNewCall() creates a local variable.
It's passing a pointer to that variable to SaveBackendCall().
SaveBackendCall() is passing a reference to the object to push_back().
push_back() implicitly makes a copy of the BackendCall and adds it to the vector.
Depending on the complexity and size of the BackendCall object, that copy may be an expensive operation. This can become especially problematic when the push_back requires the vector to be resized.
Yes, IMO it would probably be beneficial to use a vector of smart pointers to avoid unnecessary copies.

meaning of reference and pointer together?

In my project, there is a definition of a function call like this.
int32 Map(void * &pMemoryPointer)
In the calling place, the paramenter passed is void*, why cant we just receive it as a pointer itself, instead of this?
Without knowing what the Map function does, I'd guess that it sets the pointer. Therefore it has to be passed by reference.
Using a reference to a pointer, you can allocate memory and assign it to the pointer inside the function. For example
void DoSomething(int*& pointerReference)
{
// Do some stuff...
pointerReference = new int[someSize];
// Do some other stuff...
}
The other way to make functions like that is to return the pointer, but as the Map function in the question returns something else that can't be used.
Reading it backwards, this means that pMemoryPointer is a reference (&) to a pointer (*) to void. This means that whatever pointer you pass gets referenced, and any modification that the function will do to pMemoryPointer will also affect the original (passed) pointer (e.g. changing the value of pMemoryPointer will also change the value of the original pointer).
why cant we just receive it as a pointer itself, instead of this?
That's because by doing that, you are copying the pointer and any change that you'll make to the copy doesn't reflect to the original one.
void im_supposed_to_modify_a_pointer(void* ptr) { // Oh no!
ptr = 0xBADF00D;
}
int* my_ptr = 0xD0GF00D;
im_supposed_to_modify_a_pointer(my_ptr);
ASSERT(my_ptr == 0xBADF00D) // FAIL!
That's a weird function prototype IMHO, but it means
(Update) that the Map function accepts a reference to a void pointer as a parameter.
So I think, it is equivalent to declaring the function like this:
int32 Map(void** pMemoryPointer)

Pointer of array pointer objects in QT

In C++, I have a array pointer of objects like this:
vector<Articulation*> artic;
I have the next problem. When I send that vector to another class like &artic. So I have the pointer and not all the array duplicated. The problem is the next. In the new class, i have a ponter of array pointer objects
vector<Articulation*>* pArtic;
In the new class I do pArtic[i]->move(). The method is implemented in Articulation. When I do the method mov(), QT tell me that the type std::vector<_Ty> dont have an operator ->. That is because, I think, I cant access to the Articulation objects and I am trying to do move() over a vector.
Anyone knows what I must do to acces to the Articulation objects and do the move() method?
Example:
Class A:
vector<Articulation*> artic;
void A::initVector(){...}
void A::sendInfoToB(){
B nuevo();
B.send(&artic);
}
Class B:
vector<Articulation*>* pArtic
void B::send(vector<Articulacion*>* art){
pArtic=art;
}
void B::sendToC()
{
C nuevo();
C->sendTheLast(pArtic);
}
Class C:
void C::sendTheLast(vector<Articulation*>* artic)
{
string data=artic[i]->move();
//Move returns a String
}
That is the example.
The problem is, that you are calling the method move() of the i-th position of pArtic, which is a pointer to a vector of pointers. What you want to do is calling the method move of the pointer at the position i of the vector.
(*pArtic)[i]->move()
that is what you want to do, but care, this is not really safe I guess...
a better way would be to give away only the reference artic by expecting a vector<>& reference, not a pointer.
Store QT objects directly on containers (unless there is a real need of using pointers). This is because QT implements implicit sharing and COW (Copy-On-Write) which eradicates copy-overhead of containers everytime you pass them across. By passing the containers either by value or reference as need be, makes the interface simpler and easy to use.
Again, using raw-pointers in C++ is always dangerous when you have better mechanisms (like smart pointers). Smart pointers makes your program exception safe while managing the life of raw pointers.

passing a vector of pointers and erasing duplicates

I am trying to erase a vector of pointers that I pass by value into some function. The reason why I pass by value is that I plan to erase these values in numerous calls to the function. So if I pass by pointer/reference I could not achieve this.
First of all is the statement above correct?
Here is some example code:
vector<Boson*>* BosonMaker::remove_duplicates(vector<Boson*>* boson_candidates, vector<Particle*> child_candidates){
vector<Particle*> used_leptons.clear();
// This needs deleting at some point
m_unduplicated_bosons = new vector<Boson*>();
for(int i_b = 0; boson_candidates->size(); i_b++){
vector<Particle*>::iterator child1_finder = find(used_leptons.begin(), used_leptons.end(), boson_candidates->at(i_b)->Child1());
//Search pointer will reach end of collection if child isn't in the used_leptons vector
if (child1_finder == used_leptons.end()) {
vector<Particle*>::iterator child2_finder = find(used_leptons.begin(), used_leptons.end(), boson_candidates->at(i_b)->Child2());
if (child2_finder == used_leptons.end()) {
used_leptons.push_back(boson_candidates->at(i_b)->Child1());
used_leptons.push_back(boson_candidates->at(i_b)->Child2());
// And add the boson to the vector of final bosons
unduplicated_bosons->push_back(boson_candidates->at(i_b));
}
}
}
// Now make a vector of unused leptons
for (int i_l = 0; i_l < used_leptons.size(); i_l++) {
vector<Particle*>::iterator lepton_finder = find(child_candidates.begin(), child_candidates.end(), used_leptons.at(i_l));
child_candidates.erase(lepton_finder);
}
return unduplicated_bosons;
}
I would then use this member function inside the class like so
vector<Boson*> *m_boson_finals_elpair = remove_duplicates(&m_boson_electronPair_candidates, m_all_particle_candidates);
vector<Boson*> *m_boson_finals_mupair = remove_duplicates(&m_boson_muonPair_candidates, m_all_particle_candidates);
vector<Boson*> *m_boson_finals_elneutrino = remove_duplicates(&m_boson_electronNeutrino_candidates, m_all_particle_candidates);
vector<Boson*> *m_boson_finals_muneutrino = remove_duplicates(&m_boson_muonNeutrino_candidates, m_all_particle_candidates);
My question is:
Would m_all_particle_candidates which is
vector<Particle*> m_all_particle_candidates;
be different in each call of remove_duplicates?
I think I am trying to ask is the iterator lepton_finder erased from the vector and not the actual object Particle since I have passed by value?
Note: There was a typo in the remove_duplicate function. I passed by pointer and not value. it should be value
I'm a little confused about what you are saying about passing by value and passing by reference, so I'm going to give a short explanation on that first:
When passing by value, the variable that the method is called with remains unchanged (since a copy is passed into the called method). Be careful though, this case can also incur a heavy performance penalty, since the whole variable is copied! In case of a vector holding many elements this might take quite some time! Passing by value is achieved like this in C++:
When passing by reference (or more or less equivalently by pointer) the outer variable is also changed - since you're only passing a reference into the method, which is referencing the same actual space in memory as the original variable!
So basically what the difference is that in when using call by value, the original caller's value remains unchanged, while when using call by reference, a reference to the original caller's value is passed in, and therefore this value can change on both ends.
Now which method is needed simply depends on what you want to achieve. Pass by Value if the variable you're passing into the method should remain unchanged (m_all_particle_candidates in your example). Or if you need it to change, then pass by reference/pointer.
If the passed-in variable shouldn't change, but you also only need a read-only version of the variable inside the method, then the possible performance problems introduced by passing by value can be overcome by using a const reference. In you case, however, you seem to need a full copy (meaning a normal pass-by-value).
Does the code presented in the OP compile? I don't think so. In fairness, it should be passed through a compiler before posting.
typedef struct {
long double x, y, z;
} V3;
void fnExpectingPtrToVec(vector<V3> * pvec) {
}
void fnExpectingVec(vector<V3> vec) {
}
void testVecs() {
vector<V3> v;
//fnExpectingPtrToVec(v); Does not compile
fnExpectingPtrToVec(&v);
fnExpectingVec(v);
}
If it is expecting a pointer to a vector in the 2nd param, and you passed in a vector instead, then its a compile error.
When you fix the function to accept a vector, not a pointer to one, and call it with your vector it will make a copy and the repeated calls to the function will leave m_all_particle_candidates unchanged.
You're not passing the vector by value.
vector<Boson*>* BosonMaker::remove_duplicates(vector<Boson*>* boson_candidates, vector<Particle*> *child_candidates);
will pass a pointer to the vector by value. But the pointer, which is a copy of the original one, will point to the same vector as the original.
So you're basically changing the same vector as outside the call.
To pass by value, you need:
vector<Boson*>* BosonMaker::remove_duplicates(vector<Boson*> boson_candidates, vector<Particle*> child_candidates);
But be careful when doing so. Copying will occur, so you probably need to override the virtual destructor, copy constructor and assignment operator for Boson and Particle if they're not POD types.