I have the following code to store objects of type LVA in a vector.
I've implemented a method for adding a LVA Object to the vector.
First question: Is it okay if i use a reference to the LVA object in this method?
Now i want to implement a method for the deletion of a LVA object. I want to have the following method signature: void RemoveLVA(LVA& lva). How can I implement this method? i.e. How can i find the right object in the vector to delete it?
Manager.h
class Manager {
public:
Manager();
Manager(const Manager& orig);
virtual ~Manager();
vector<LVA> GetLvas() const;
void AddLva(LVA& lva);
private:
vector<LVA> lvas;
};
Manager.cpp:
#include "Manager.h"
Manager::Manager() {
}
Manager::Manager(const Manager& orig) {
}
Manager::~Manager() {
}
vector<LVA> Manager::GetLvas() const {
return lvas;
}
void Manager::AddLva(LVA& lva) {
lvas.push_back(lva);
}
Is it okay if i use a reference to the LVA object in AddLva(LVA& lva)?
Yes, std::vector will have a copy of your original object after push_back() is complete.
How can I implement RemoveLVA(LVA& lva)?
You will need to find the object in your vector. (You may use std::find() if operator==() is defined for LVA.) Then invoke the erase() function for your vector.
Is it okay if i use a reference to the LVA object in this method?
No problem. You are actually doing a copy by a push_back operation.
Without knowing more about LVA, it's hard to be precise, but
you probably want a const reference for AddLva, since you're
not modifying it in the function (and you may want to pass
a temporary).
For removal: you'll have to define some sort of
equivalence function over LVA is you want to remove a matching
element. This can be LVA::operator==, or some other object or
function: in the first case, you use std::find to find the
position, and in the second, std::find_if. If the vector can contain
more than one matching element, you might want to look into std::remove or std::remove_if.
Your insertion method is right, but don't forget that only a copy from your LVA object is inserted in the vector. it means than in the RemoveLVA method, you will need to use somthing like an operator== overload to std::find the vector's object which matches your parameter, and then deleting it.
You may prefer to insert pointers or std::shared_ptr of LVA in your vector. No object copy will then occur, and the search of an object will fall back to a comparison of pointer, given you keep the pointer somewhere else in your program (2 objects with same contents and different stack or heap locations would then compare to false).
Yes, AddLva can take a reference, although it would typically take a const reference:
void Manager::AddLva(const LVA& lva) {
lvas.push_back(lva);
}
Note however that if you are expecting that the reference is added to the vector, this isn't doing that. A copy of the object lva refers to is made, and that copy is added to the vector.
Yes it's Ok to pass the LVA object as ref in your add and remove method. You could also declare those parameters as 'const' because I suppose add and remove will not affect the object .
for the remove method
void RemoveLVA(const LVA& lva)
{
std::vector<LVA>::iterator position =
std::find(lvas.begin(), lvas.end(), lva);
if (position != lvas.end())
{
lvas.erase(position);
}
}
but LVA class must have an == operator.
good luck.
Related
I am trying to temporary store a vector of unique pointers and switch them between 2 objects. Here I try to move the ownership of the vector to a temporary vector named oldcards.
std::vector<std::unique_ptr<Building>> oldCards = std::move(player.getBuildingCards());
player.setBuildingCards(std::move(otherPlayer.getBuildingCards()));
otherPlayer.setBuildingCards(std::move(oldCards));
Player.cpp
std::vector<std::unique_ptr<Building>> const& Player::getBuildingCards() const
{
return this->buildingCards;
}
void Player::setBuildingCards(std::vector<std::unique_ptr<Building>> buildingCards)
{
this->buildingCards = std::move(buildingCards);
}
Player.h
std::vector<std::unique_ptr<Building>> buildingCards;
To conclude: I want to swap 2 vectors, I want player to have the ownership of the vector of otherPlayer and vice versa. However, I get the: attempting to reference a deleted function error. How can I achieve this?
I am trying to temporary store a vector of unique pointers and switch them between 2 objects.
Why? Using std::vector::swap would accomplish the same thing with less effort. (Note that this swap most likely should occur within a member function, so there would be no need to use the public accessor functions.)
std::vector<std::unique_ptr<Building>>const& Player::getBuildingCards() const
This returns a const reference. You are not allowed to change something marked const. Moving data out of something counts as changing that something, so moving from getBuildingCards() is not allowed.
void Player::setBuildingCards(std::vector<std::unique_ptr<Building>> buildingCards)
This function takes a copy of a vector as a parameter. Since a vector of unique_ptr cannot be copied, this function signature is DOA. (For the intended purpose, you would want the type of the parameter to be std::vector<std::unique_ptr<Building>>&& to indicate that you will be moving from the parameter.)
You cannot move from cons T& so copy constructor of oldCards is called which is of course deleted. player.getBuildingCards() cannot change the player instance anyway because you marked it as const.
Cleanest solution (at least according to me) would to implement swapBuildingCards friend function:
class Player
{
//...
std::vector<std::unique_ptr<Building>> buildingCards;
friend static void swapBuildingCards(Player& p1, Player &p2)
{
using std::swap;
swap(p1.buildingCards,p2.buildingCards);
}
};
Suppose I have the following:
class Map
{
std::vector<Continent> continents;
public:
Map();
~Map();
Continent* getContinent(std::string name);
};
Continent* Map::getContinent(std::string name)
{
Continent * c = nullptr;
for (int i = 0; i < continents.size(); i++)
{
if (continents[i].getName() == name)
{
c = &continents[i];
break;
}
}
return c;
}
You can see here that there are continent objects that live inside the vector called continents. Would this be a correct way of getting the object's reference, or is there a better approach to this? Is there an underlying issue with vector which would cause this to misbehave?
It is OK to return a pointer or a reference to an object inside std::vector under one condition: the content of the vector must not change after you take the pointer or a reference.
This is easy to do when you initialize a vector at start-up or in the constructor, and never change it again. In situations when the vector is more dynamic than that returning by value, rather than by pointer, is a more robust approach.
I would advice you against doing something like the above. std::vector does some fancy way of handling memory which include resizing and moving the array when it is out of capacity which will result in a dangling reference. On the other hand if the map contains a const vector, which means it is guaranteed not to be altered, what you are doing would work.
Thanks
Sudharshan
The design is flawed, as other have pointed out.
However, if you don't mind using more memory, lose the fact that the sequence no longer will sit in contiguous memory, and that the iterators are no longer random access, then a drop-in replacement would be to use std::list instead of std::vector.
The std::list does not invalidate pointers or references to the internal data when resized. The only time when a pointer / reference is invalidated is if you are removing the item being pointed to / referred to.
I'm new to C/C++, so people excuse me if this is a noob question.
I have a controller class, which has a private member variable which is a vector<Contact> contacts. The class has methods which allow us to change the state of this vector (standard CRUD operations).
The class has a public method called get_contacts() which returns this private vector of objects:
std::vector<Contact> Contacts_Controller::get_contacts() const {
return this->contacts;
}
I have a method which adds the contact to this private vector via push_back(). The issue is that if the add_contact() method uses the accessor method, then the class variable does not get updated:
void Contacts_Controller::add_contact(const Contact &contact) {
this->get_contacts().push_back(contact);
}
I assume this is a memory issue, perhaps I have some issues with my use of const or I'm not correctly using references, because the following code works exactly as expected:
void Contacts_Controller::add_contact(const Contact &contact) {
this->contacts.push_back(contact);
}
Using either method won't return any errors, but if I then request the vector of contacts after using the first method it'll be empty, whereas the second method correctly adds data to the vector.
Again, sorry if this is a noob question, but I'm completely stumped, and I wouldn't know what to search for! How would I fix this referencing issue?
"The class has a public method called get_contacts() which returns this private vector of objects"
Nope, it returns a copy. You need to return by reference to get the actual member:
std::vector<Contact>& Contacts_Controller::get_contacts(){
return this->contacts;
}
Note that I removed the const, otherwise you'd have to mark the return as const also and you wouldn't be able to modify it.
The issue is that your function is returning the vector by value, which means the calling function gets a copy.
When you call push_back() on it, only the copy gets the extra member.
Your function could return a reference. Then your user can call push_back(). If it is a member variable of your class and you are returning a non-const reference (which you must to allow the modification) your function will probably also be non-const.
Thus:
std::vector<Contact> & Contacts_Controller::get_contacts() // not const
{ return this->contacts; }
You can also have a read-only version, as an overload.
std::vector<Contact> const & Contacts_Controller::get_contacts() const
{ return this->contacts; }
This version allows read-only access to the contacts and can also be a const member function.
When you call get_contacts, you return a copy of this->contacts. If you want to share a vector, either return a reference to it (but you must be sure that your reference will stay valid so your class instance won't be moved or copied), or use a smart pointer to dynamically allocate the space for your vector and extend its lifetime until the last reference to it has been destructed. In this case use a member with type std::shared_ptr<std::vector<Contact> >
I create a vector A and want to copy to a vector B in another class by using below method, is it a correct way? The vector A may be destroyed! I searched in google, but not found the good solution and meaningful explanation. Thanks everyone
void StateInit(vector<CButton*> listBtn)
{
_m_pListBtn = listBtn;
};
Yes and no, you are passing the vector by value:
void StateInit(vector<CButton*> listBtn)
{
_m_pListBtn = listBtn;
};
Wich means that listBtn is a copy of vector A (asuming we are calling vector A the one passed as parameter of StateInit), if you delete vector A, vector B will still have the collection of pointers and they will be valid since the destruction of a vector of pointers doesnt delete the pointed objects because it cant possible now how (should it call, delete, delete[], free?).
Do keep in mind that if you modify/delete one of the elements from vector A (using the pointers on the vector), that element will be modified in vector B (since its a pointer to the same element).
Im not sure what is your intend with this, but if you want to copy the whole vector, you should implement a clone mechanism for the objects and then copy them using transform:
class cloneFunctor {
public:
T* operator() (T* a) {
return a->clone();
}
}
Then just:
void StateInit(vector<CButton*> listBtn)
{
transform(listBtn.begin(), listBtn.end(), back_inserter(_m_pListBtn), cloneFunctor());
};
IF your intention is not to clone it but to share the pointers you should pass the vector as pointer or reference:
void StateInit(const vector<CButton*>& listBtn)
{
_m_pListBtn = listBtn;
};
A better way is to iterate on the new vector and push_back the elements to your vector.
See example code: std::vector::begin
Coming from C#, where class instances are passed by reference (that is, a copy of the reference is passed when you call a function, instead of a copy of the value), I'd like to know how this works in C++. In the following case, _poly = poly, is it copying the value of poly to _poly, or what?
#include <vector>
using namespace std;
class polynomial {
vector<int> _poly;
public:
void Set(vector<int> poly);
};
void polynomial::Set(vector<int> poly) {
_poly = poly; <----------------
}
poly's values will be copied into _poly -- but you will have made an extra copy in the process. A better way to do it is to pass by const reference:
void polynomial::Set(const vector<int>& poly) {
_poly = poly;
}
EDIT I mentioned in comments about copy-and-swap. Another way to implement what you want is
void polynomial::Set(vector<int> poly) {
_poly.swap(poly);
}
This gives you the additional benefit of having the strong exception guarantee instead of the basic guarantee. In some cases the code might be faster, too, but I see this as more of a bonus. The only thing is that this code might be called "harder to read", since one has to realize that there's an implicit copy.
This will do a shallow-copy of the vector of ints. This will generally work as you would expect (_poly will end up containing the same values as poly).
You would see some strange behaivor if you had pointers (as they would be copied by value).
In general, you would want to pass that parameter by const reference:
void polynomial::Set( const vector<int>& poly )
In this case, passing by const reference will not affect the outcome and will be more efficient since it will eliminate an unneeded copy of the vector being passed into the method.
This will copy the entire vector. Assignment is by value in C++. If you are assigning a pointer, the pointer value is assigned. References may not be reassigned to refer to another object once initialized, so assignment of them alters the referent object.
The copy operator for vectors will copy the contents of the vector over.
There are three possibilities:
Pass by value
void someFunction(SomeClass theObject);
Pass a pointer
void someFunction(SomeClass *theObject);
Pass by reference
void someFunction(SomeClass &theObject);
Your vector will be copied.
What's actually going on is that the "=" operator of vector has been overloaded to do the actual copy.
Yes, the line you point to is copying the entire vector. Furthermore, there will be a copy on the function call, as well, since that's not const.
Basically, if the vector has any size to it, this is VERY expensive.
Unless you assign or pass a parameter by reference (using the & prefix) you are passing by value. For classes, this means that a copy of the object is constructed using either a supplied or implicitly generated (shallow) copy constructor for the type. This can be expensive - and is often undesirable.
In your example, the vector is copied twice - once when it is passed as a parameter to the Set() method, and again when it is assigned to the _poly member.
You could avoid the first copy by passing the vector by reference:
void polynomial::Set(const vector<int>& poly) // passes the original parameter by reference
{
_poly = poly; // still makes a copy
}