c++ help passing a vector index to a function - c++

I know how to pass a vector to a function, but how do I pass a vector index to a function, or at least specify which index the function is modifying. For example, I'm working on a Car class and it has a vector if wheel pointers and in order to remove one of the wheels my function looks like this:
Wheel& remove() {
for (int i = 0; i < wheels.size(); i++) {
if (wheels[i].position == wheels.at(i)) {
??
}
what do I need to pass to the function in order to specify which wheel I want removed? When a wheel is removed, the position where it was is still there and can be filled by another wheel. Let's say for example the car had 4 wheels...if I wanted to remove the 2nd index in the wheel vector, what does the function argument for remove() need to take in order to do it? Should I pass in the vector and then the specific index....and if so, what does the syntax look like?

You can just pass an integer to specify which one you would like to remove
void RemoveWheel(int i)
{
if( (i<wheels.size()) and (i>=0) )
wheels.erase(wheels.begin()+i);
}
http://www.cplusplus.com/reference/stl/vector/erase/
If you want to leave the space for another wheel than you should define wheels as a vector of pointers and just delete object at the i-th position and save NULL instead of it.
vector<Wheel *> wheels;
void RemoveWheel(int i)
{
if( (i<wheels.size()) and (i>=0) ) {
delete wheels[i];
wheels[i] = 0;
}
}

Your question is not entirely clear to me, but to remove an element from a vector, given an index i, you can do this:
wheels.erase(wheels.begin() + i);
But this would be better:
auto e = std::remove_if(wheels.begin(), wheels.end(),
[](const Wheel & wheel) {
return wheel.position == wheel;
});
wheels.erase(e,wheels.end());
Although I'm not sure if you want to remove every element that fits that criteria, or just the first. If you would show the logic in pseudocode of what you want to do, that would help.

Related

Vector of structure returns only last value

Sorry I can't paste the full code but I will try my best to explain the problem. I have a vector of structure. I am passing the vector to a function which fills the vector with structure and returns the vector. But when I try to access the vector elements, I get only the last element inserted. I think the problem is somewhere that I am storing the address of the structure and hence vector only retains the last value but i am not sure how to correct this.
Here is my structure:
struct NA
{ element1;
element2;
};
Here is how I pass my vector after declaring it:
Vector<NA> del;
func(del);
Here is my function: ( q is a variable having results from a stored procedure
func(Vector<NA> &dels)
{
NA& del(*new NA);
while(q.nextquery())
{
while(q.nextrow())
{
q.bind(del.element1);
q.bind(del.element2);
dels.insert(&del);
}
return dels.entries()
}
NA& del(*new NA);
while(q.nextquery())
dels.insert(&del);
Obviously, you are creating only one del object, but you insert it many times in the same vector. At the end, all you vector's entries will point to the same object.
What you want is probably to create a new del object for each entry in your vector. therefore, put the creation statement inside the loop.
func(Vector<NA> &dels)
{
while(q.nextquery())
{
while(q.nextrow())
{
NA& del(*new NA); // <-- Here
q.bind(del.element1);
q.bind(del.element2);
dels.insert(&del);
}
return dels.entries()
}
func() is pushing multiple copies of a single pointer to a single dynamically allocated object into the vector. Each loop iteration is modifying that same object, so every entry in the vector will end up pointing to the data of the last query record that was read.
Try something more like this instead:
func(Vector<NA> &dels) {
while(q.nextquery()) {
while(q.nextrow()) {
NA *del = new NA;
q.bind(del->element1);
q.bind(del->element2);
dels.insert(del);
}
}
return dels.entries();
}
On the other hand, why are you storing pointers in the vector? And using a non-standard vector class? It would be safer to store actual objects into a standard std::vector class instead:
void func(std::vector<NA> &dels) {
while(q.nextquery()) {
while(q.nextrow()) {
NA del;
q.bind(del.element1);
q.bind(del.element2);
dels.push_back(del);
}
}
}

Own vector class for arduino (c++)

I added also void Clear()-method.
https://redstoner.com/forums/threads/840-minimal-class-to-replace-std-vector-in-c-for-arduino
https://forum.arduino.cc/index.php?topic=45626.0
I'm asking about this Vector class.
void push_back(Data const &x) {
if (d_capacity == d_size) resize();
d_data[d_size++] = x;
}; // Adds new value. If needed, allocates more space
How to add "insert"-method to this Vector class (arduino use C++ but not have a standard vector methods)?
Vector<Sensor*> sensors;
I have a another class Sensor and I use vector like this.
push.back(new Sensor (1,1,"Sensor_1",2));
Is it possible to add values one by one to this vector class? And how to do it?
I like to ask also other question.
How can I call delete/call destructor for this Vector "sensors" so all pointers are deleted? Or sensors vector is deleted? I want to clear the data and then add data to it.
If you want to add an item to the end of the vector, use the push_back method you've quoted above. If you want to add an item somewhere else in the vector, you'll need to add your own method which re-sizes if necessary, shifts the elements above the insert location up one place and then copies the new element into the correct slot. Something like this (untested):
void insert_at(size_t idx, Data const &data) {
assert(idx < d_size);
if (d_capacity == d_size) {
resize();
}
for (size_t i = d_size; i > idx; --i) {
d_data[i] = std::move(d_data[i - 1]);
}
d_data[idx] = data;
++d_size;
}
As Nacho points out, you might be better off with a linked list if you're going to do a lot of these insert operations, especially if the data you're storing is large and/or has a complex move operator.

Can't push_back a class into an object vector inside a for loop

I cannot call a function that does a push_back into a vector
void GameState::InitialiseBullet(float x, float y, float vx, float vy)
{
Bullet* bullets = new Bullet();
bullets->SetSize(5.f, 20.f);
bullets->AddFrame("./images/bullet.png");
bullets->Play();
bullets->SetX(x);
bullets->SetY(y);
bullets->velocityX = vx;
bullets->velocityY = vy;
bullets->isActive = true;
gameObjects.push_back(bullets);
}
when it is inside the following for loop
for (auto& object : gameObjects)
{
//Determine the type at runtime
if (dynamic_cast<Player*>(object) != 0)
{
//Process player-specific logic
PlayerLogic(dynamic_cast<Player*>(object), a_fTimeStep);
}
//Determine the type at runtime
if (dynamic_cast<Bullet*>(object) != 0)
{
//Process bullet-specific logic
BulletLogic(dynamic_cast<Bullet*>(object), a_fTimeStep);
}
if (dynamic_cast<Enemy*>(object) != 0)
{
//Process enemy-specific logic
Enemy* enemy = dynamic_cast<Enemy*>(object);
EnemyLogic(enemy, lowerAliens);
if (enemy->GetIsActive() == true)
{
allDead = false;
}
}
//Update and draw our objects
object->Update(a_fTimeStep);
object->Draw();
}
The piece of code that calls the function:
if (createBullet == true)
{
InitialiseBullet(bulletX, bulletY, 0, 500);
createBullet = false;
}
That code works when outside the for loop. However, I need the for loop to provide access to each of my player, enemy and bullet objects. Is there a way to push_back to a vector inside a for loop that is based on the same vector? I get a "Expression: Vector iterators incompatible" error when it's inside the loop. Any ideas? New to C++ programming.
It looks like you are pushing into the same vector you are iterating, that means, you are forcing items realocation and iterator invalidation; in other words - your data moves to different location and used iterator becomes invalid.
I rarely see situation where you really need to iterate and append same vector, so take a look into your code again.
If you really need to do that, iterate this way:
for (size_t i = 0; i < gameObjects.size(); ++i)
{/*Some code*/}
Also using this method you should use gameObjects[i]. instead of it->
It's just a vector of pointers, so it's not very big.
The objects being added is probably even smaller.
You could make a copy of the vector and iterate over the copy while inserting into the real one.
You could put new items into a new, empty vector while you iterate, and then splice them onto the real one at the end.
To delete objects, you could do either of those things, or you could simply set a flag "isZombie" and then remove all the zombies at the end.
These aren't the only answers, but they all work.
When using iterators to loop through your vector you can't in this 'for-loop' modify the vector.
A quick google gave me this; which seemd to fit your case pretty well.
Probably because the push_back ... caused an internal
reallocation in the vector thus all its iterators were invalidated.
Source: http://www.cplusplus.com/forum/beginner/64854/
Do I understand you right when I'm assuming your using iterators due to your error message.
One question you should ask yourself is why you would ever want to add instances to this vector, maybe you should rethink your design slightly to avoid this.

Issues with returning map loop

I have a map that contains a string to sprite association. This function is used to return the sprite to draw on the screen. Here is the function:
sf::Sprite LoopSprite()
{
for (std::map<std::string,sf::Sprite>::iterator it=SpriteMap.begin(); it!=SpriteMap.end(); ++it)
{
return it->second;
}
}
I used to have these in a vector which made loops for drawing easy, but I wanted to use a map to allow easier recognition for maintaining code. The function above only allows one image from the map to be drawn. Is there something wrong with this function?
sf::Sprite LoopSprite(int element)
{
return vec[element];
}
As pointed this works because it takes an element so there is only one return, but I want the same result except with the map. The issue is that it is easy to send in a 0-vec.size. My only idea is to have a vector of strings to allow easy looping.
Your function will simply return in the first iteration, returning only the first element in the map.
You say in the comments that originally, when you were using a vector, the function took an int argument and returned that element. If you still want the function, you can achieve the same with a map like so:
sf::Sprite LoopSprite(std::string key)
{
return SpriteMap[key];
}
If you want to iterate over the elements of the map inside LoopSprite, then you'll need to move the lines of code that actually do something with each element into the function:
void LoopSprite()
{
for (std::map<std::string,sf::Sprite>::iterator it=SpriteMap.begin(); it!=SpriteMap.end(); ++it)
{
// Do something with it->second
}
}
First of all you are returning local variable which is not allowed. Even after returning from the function it may be null or invalid.
You are only returning this part SpriteMap.begin() which is actually useless. This code is much easier.
sf::Sprite LoopSprite(string key)
{
std::map<std::string,sf::Sprite>::iterator it = SpriteMap.begin();
while(it!=SpriteMap.end())
{
if(check) // check if this is your desired key
return value;
++it;
}
return null;
}
map is used usually in a simple way:
string key = "keyItem";
sf::Sprite ans = SpriteMap[key];

Can't Save structure content

I have the next problem:
I created the structure:
struct Series : vector<Candle>
{
Security Sec;
int LookFor;
int TF;
int Corrector;
string ID;
int line;
Series(){};
Series (int _lookfor);
void Update();
};
Constructor:
Series::Series (int _lookfor)
{
LookFor=_lookfor;
for (int i = 1; i<=LookFor; i++)
{
Candle cantype = Candle(i);
push_back(cantype);
}
}
So, then we call this construcor it fills object by candle-values. LookFor - is a number of candles in the vector-series.
After initialization i want update this serie (if there is more new candle, i want delete last one and insert new on the begining of vector-serie)
void Series::Update()
{
if (size()==LookFor)
{
if (newer(cantype,c1))
{
Candle cantype = Candle(1);
Candle c1 = at(0);
pop_back();
emplace(begin(),cantype);
}
}
I need to initialize a vector of these series:
vector vec;
vec.push_back(Series(3));
And constructor does its job, everithing is fine.
But then i update them:
for (size_t x =0; x<=size()-1;x++) vec[x].Update();
I have a problem: it cann't save changes in vector. In Update method everithing is fine, it inserts needed candle in itself, but then method is ended - the state of vector (each element of vec) has no changes. In method we see changes, but after it vector become after constructor-like, the state still the same.
Tell me, please, what am I doing wrong?
As others already mentioned, do not derive from these containers (could cause nasty errors like missing dtor calls and memory leaks, no virtual destructor is present in these containers). Instead, add the vector as a member or leave it as is, if you do private inheritance.
You may use the iterator interface for such containers:
for(std::vector<Series>::iterator sIt = vec.begin();sIt != vec.end();++sIt) sIt->Update();
For your task, consider using a deque or a list as a circular buffer instead of the vector for the Candles. It would perform better for insertions and therefore allows you to use push_front() instead of emplace() or insert().
Alternatively, you could hold an index of the vector element just past the last element (which should be the first) and just assign the new candle, et voilĂ , you've got a dense circular buffer.
There are implementations of such circular buffers, for example the one of boost:
http://www.boost.org/doc/libs/1_52_0/libs/circular_buffer/doc/circular_buffer.html
Despite logic issues, which could prevent the modification in certain states, I can't see, why your code doesn't work at all, at least not when I went through the snippets you posted.