object from vector with structs - c++

i 'm pretty new to c++, can you help me with pointers ? i have a struct
struct Slice
{
Slice(): {}
SliceObj *slObj;
};
and vector:
std::vector<Slice> slices;
So on mouce touch i want to take this object to change his public var:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice slice0 = slices[0];
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}
And of coure of course when in drag method i make : slObj->rect.x = x+0.1;, it doesn't make anything good.
Please, help me with this, i can't understand how to carefully get obj with * from another object from vector and then carefully change it's param;
Trouble is in "how to carefully get SliceObj from slice0", not address of var, but this instance.
So here i need to get slObj param, that in future i can make slObj.rect.x = 1;
UPDATE:
when i make slObj->drag method i always see only strange number like:
but then, when glutPostRedisplay called and it's redraw on method
void SliceObj::draw(SliceObj *slObj)
then it's all good!

You should access the element through the iterator:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice& slice0 = *it //Get the element using iterator (Note the reference, is to avoid copy)
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}
However, if you have a C++11 capable compiler, you could simplify things using range-based for loop:
for( auto& slObj : slices )
{
liceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}

You need to use the iterator to get the element from the vector. Here you are always getting the first element. Try this:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice slice0 = *it //Get the element using iterator
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}

Related

C++ LRU cache - need suggestions on how to improve speed

The task is to implement an O(1) Least Recently Used Cache
Here is the question on leetcode
https://leetcode.com/problems/lru-cache/
Here is my solution, while it is O(1) it is not the fastest implementationcould you give some feedback and maybe ideas on how can I optimize this ? Thank you !
#include<unordered_map>
#include<list>
class LRUCache {
// umap<key,<value,listiterator>>
// store the key,value, position in list(iterator) where push_back occurred
private:
unordered_map<int,pair<int,list<int>::iterator>> umap;
list<int> klist;
int cap = -1;
public:
LRUCache(int capacity):cap(capacity){
}
int get(int key) {
// if the key exists in the unordered map
if(umap.count(key)){
// remove it from the old position
klist.erase(umap[key].second);
klist.push_back(key);
list<int>::iterator key_loc = klist.end();
umap[key].second = --key_loc;
return umap[key].first;
}
return -1;
}
void put(int key, int value) {
// if key already exists delete it from the the umap and klist
if(umap.count(key)){
klist.erase(umap[key].second);
umap.erase(key);
}
// if the unordered map is at max capacity
if(umap.size() == cap){
umap.erase(klist.front());
klist.pop_front();
}
// finally update klist and umap
klist.push_back(key);
list<int>::iterator key_loc = klist.end();
umap[key].first = value;
umap[key].second = --key_loc;
return;
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
Here's some optimizations that might help:
Take this segment of code from the get function:
if(umap.count(key)){
// remove it from the old position
klist.erase(umap[key].second);
The above will lookup key in the map twice. Once for the count method to see if it exists. Another to invoke the [] operator to fetch its value. Save a few cycles by doing this:
auto itor = umap.find(key);
if (itor != umap.end()) {
// remove it from the old position
klist.erase(itor->second);
In the put function, you do this:
if(umap.count(key)){
klist.erase(umap[key].second);
umap.erase(key);
}
Same thing as get, you can avoid the redundant search through umap. Additionally, there's no reason to invoke umap.erase only to add that same key back into the map a few lines later.
Further, this is also inefficient
umap[key].first = value;
umap[key].second = --key_loc;
Similar to above, redundantly looking up key twice in the map. In the first assignment statement, the key is not in the map, so it default constructs a new value pair thing. The second assignment is doing another lookup in the map.
Let's restructure your put function as follows:
void put(int key, int value) {
auto itor = umap.find(key);
bool reinsert = (itor != umap.end());
// if key already exists delete it from the klist only
if (reinsert) {
klist.erase(umap[key].second);
}
else {
// if the unordered map is at max capacity
if (umap.size() == cap) {
umap.erase(klist.front());
klist.pop_front();
}
}
// finally update klist and umap
klist.push_back(key);
list<int>::iterator key_loc = klist.end();
auto endOfList = --key_loc;
if (reinsert) {
itor->second.first = value;
itor->second.second = endOfList;
}
else {
const pair<int, list<int>::iterator> itempair = { value, endOfList };
umap.emplace(key, itempair);
}
}
That's as far as you can probably go by using std::list. The downside of the list type is that there's no way to move an existing node from the middle to the front (or back) without first removing it and then adding it back. That's a couple of unneeded memory allocations to update the list. Possible alternative is that you just use your own double-linked list type and manually fixup the prev/next pointer yourself.
Here is my solution, while it is O(1) it is not the fastest implementation
could you give some feedback and maybe ideas on how can I optimize this ? Thank you !
Gonna take on selbie's point here:
Every instance of if(umap.count(key)) will search for the key and using umap[key] is the equivalent for the search. You can avoid the double search by assigning an iterator which points to the key by a single std::unordered_map::find() operation.
selbie already gave the code for int get()'s search, here's the one for void put()'s one:
auto it = umap.find(key);
if (it != umap.end())
{
klist.erase(it ->second);
umap.erase(key);
}
Sidecase:
Not applicable for your code as of now due to lack of input and output work, but in case you use std::cin and std::cout, you can disable the synchronization between C and C++ streams, and untie cin from cout as an optimization: (they are tied together by default)
// If your using cin/cout or I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

How do I properly pass iterator by reference?

I have a game where I check collision between bullets and enemies which I store as 2 vector containers. People say if you're gonna erase an element in the for loop you better use iterators and so I did. But I have a problem now with passing the iterator to a function. The thing is I don't necessarily need to erase the element so it has to be a bit more complex.
This is the way I check collision. "CircularCollision" works fine, no mistakes there.
void ResolveColision(Weapon &weap, Map &map)
{
std::vector<Bullet> bullets = weap.GetBullets();
if (!bullets.empty())
{
for (std::vector<Bullet>::iterator i = bullets.begin(); i != bullets.end(); ++i)
{
std::vector<Enemy> enemies = map.GetEnemies();
if (!enemies.empty())
{
for (std::vector<Enemy>::iterator j = enemies.begin(); j != enemies.end(); ++j)
{
if (CircularCollision((*i), (*j)))
{
weap.DeleteByIndex(i);
map.TakeDamageByIndex(j, weap.GetDamage());
std::cout << "HIT!\n";
}
}
}
}
}
}
Here's the method which is supposed to decrease the health of an enemy:
void Map::TakeDamageByIndex(std::vector<Enemy>::iterator &itr, int damage)
{
(*itr).SetHealth((*itr).GetHealth() - damage);
}
Here's the method which deletes the bullet:
void Weapon::DeleteByIndex(std::vector<Bullet>::iterator &itr)
{
destroySprite((*itr).GetSprite());
bullets.erase(itr);
}
I'm sure it looks horrible and it shouldn't work but I have no idea how to do it properly. Please help!
Also, both methods work properly when the for loops operate with indexes (e.g. bullets[i]), in that case the problem is with "Vector subscript out of range" error.
In DeleteByIndex(), change this:
bullets.erase(itr);
To this:
itr = bullets.erase(itr);
std::vector::erase() returns an iterator to the next remaining element after the element that was erased. That next element is where your outer loop needs to continue from on its next iteration.
As such, you need to change your outer loop from a for to a while instead, or else you will skip elements (in fact, your original code suffers from that problem when you were still using indexes):
void ResolveColision(Weapon &weap, Map &map)
{
std::vector<Bullet> bullets = weap.GetBullets();
std::vector<Bullet>::iterator bullerItr = bullets.begin();
while (bullerItr != bullets.end())
{
std::vector<Enemy> enemies = map.GetEnemies();
bool wasAnyHit = false;
for (std::vector<Enemy>::iterator enemyItr = enemies.begin(); enemyItr != enemies.end(); ++enemyItr)
{
if (CircularCollision(*bulletItr, *enemyItr))
{
wasAnyHit = true;
weap.DeleteByIndex(bulletItr);
map.TakeDamageByIndex(enemyItr, weap.GetDamage());
std::cout << "HIT!\n";
break;
}
}
if (!wasAnyHit)
++bulletItr;
}
}
That being said, I would suggest replacing the inner loop with std::find_if() instead. And renaming DeleteByIndex() and TakeDamageByIndex() since they don't take an index anymore. In fact, I would not pass an iterator to TakeDamage...() at all, pass the actual Enemy object instead. Or better, move TakeDamage() into Enemy itself.
Try something more like this:
void ResolveColision(Weapon &weap, Map &map)
{
auto bullets = weap.GetBullets();
auto bulletItr = bullets.begin();
while (bulletItr != bullets.end())
{
auto enemies = map.GetEnemies();
auto &bullet = *bulletItr;
auto enemyHit = std::find_if(enemies.begin(), enemies.end(),
[&](Enemy &enemy){ return CircularCollision(bullet, enemy); }
);
if (enemyHit != enemies.end())
{
weap.DeleteBulletByIterator(bulletItr);
enemyHit->TakeDamage(weap.GetDamage());
std::cout << "HIT!\n";
}
else
++bulletItr;
}
}
void Enemy::TakeDamage(int damage)
{
SetHealth(GetHealth() - damage);
}
void Weapon::DeleteBulletByIterator(std::vector<Bullet>::iterator &itr)
{
destroySprite(itr->GetSprite());
itr = bullets.erase(itr);
}
A few other comments in addition to Remy Lebeau’s answer.
It’s as efficient to pass a STL iterator by value as by reference, so the only reason you would need to pass one by reference is: when you intend to change the index and you want that change to be visible in the caller’s scope. (For example, a UTF-8 parser needs to consume anywhere from one to four bytes.) Since this code doesn’t need to do that, you’re better off just passing the iterator by value.
In general, if you aren’t modifying the variable you pass by reference, you should pass by const reference instead. In the case of Enemy::TakeDamage(), the only thing you do with the iterator is dereference it, so you might as well just pass in an Enemy& and call it with *i as the parameter.
The algorithm is not very efficient: if you delete a lot of items near the start of the list, you would need to move all remaining items of the array multiple times. This runs in O(N²) time. A std::list, although it has a high overhead compared to std::vector, can delete elements in constant time, and might be more efficient if you have a lot of insertions and deletions that are not at the end. You might also consider moving only the objects that survive to a new list and then destroying the old one. At least this way, you only need to copy once, and your pass runs in O(N) time.
If your containers store smart pointers to the objects, you only have to move the pointers to a new location, not the entire object. This will not make up for the overhead of lots of heap allocations if your objects are small, but could save you a lot of bandwidth if they are large. The objects will still be automatically deleted when the last reference to them is cleared.
You could do something like this:
void delByIndex(vector<int>::iterator &i, vector<int>& a)
{
a.erase(i);
}
int main()
{
vector<int> a {1,5,6,2,7,8,3};
vector<int> b {1,2,3,1};
for(auto i=a.begin();i!=a.end();)
{
bool flag = false;
for(auto j=b.begin();j!=b.end();j++)
{
if(*i==*j)
{
flag = true;
}
}
if(flag)
{
delByIndex(i, a);
}
else
i++;
}
for(auto i:a)
cout << i << " ";
return 0;
}
Be careful when using erase as it will change the size of the vector and also invalidates the vector iterator.

Compare every item in a vector to every other item, while deleting some elements?

I need to write a function which compares every element of an std::vector<std::shared_ptr<Shape >> shapes_ to every other element determine if the shapes overlap, and then remove one of the overlapping shapes if so. Here is what I've got currently:
class Shape {
public:
...
virtual bool overlaps(const std::shared_ptr<Shape>&) const = 0;
...
};
class Square : public Shape { ... } ;
class Circle : public Shape { ... } ;
And utilizing these classes:
std::vector<shared_ptr<Shape>> shapes_;
// ... some code populates the array
for (auto& shape : shapes_) {
// Compare to every other shape
for (unsigned long j = 0; j < shapes_.size(); j++) {
// If they overlap and they aren't the same shape
if (shape->overlaps(shapes_.at(j)) && shape!=shapes_.at(j)) {
shapes_.erase(shapes_.begin() + j);
}
}
}
However I keep running into problems where I'm iterating over a null (removed) element, or beyond the end of the array or something. I keep re configuring it this way or the other but one of these problems keeps popping up.
What would be considered the most sensible, clean way to deal with a problem where you're comparing every element of a vector to every other element, and in the process sometimes deleting some elements?
Additionally, what if I would like to print some information about each overlap that is found, and the shape that is removed?
You can use erase-remove idiom:
auto it = vec.begin();
auto end = vec.end();
while( std::distance( it, end ) > 1 ) {
auto condition = [shape=*it]( const auto &other ) { return shape->overlaps( other ); };
end = std::remove_if( ++it, end, condition );
}
vec.erase( end, vec.end() );
this lambda syntax requires C++14, but it can be easily modified to work with C++11 if necessary (by introducing temp variable shape before lambda for example, or capturing it by value not reference).

c++ refer to consecutive values with iterator

I want to calculate values of w, being the distance between two points, iteratively. In my Aclass i have members like x, y and this w. So I use Pitagoras Theorem, but how to do it smoothly using iterators? This is my try, but I don't know how using iterator reference to the "previous than pointed" value.
Please help :)
Aclass temp;
for (ars::cClassC::iterator it = New_Diff.begin(); it != New_Diff.end(); it++)
{
temp.w = sqrt(((it->getX()-(it->getX()-1))^2+((it->getY()-(it->getY()-1)));
New_Diff.push_back(temp);
}
Just save the previous element:
ars::cClassC::iterator it_prev = New_Diff.end();
for (ars::cClassC::iterator it = New_Diff.begin(); it != New_Diff.end(); it++) {
if (it_prev != New_Diff.end()) {
//do the stuff here, now you have the two elements
}
it_prev = it;
}

How to change a vector item in C++?

I've got a vector of structs in C++ and I would like to modify each item individually. I found that doing SomeStruct info = myVector[i] gives me a copy of the item, so if I modify it nothing will be changed. So right now I'm resetting the item like that: myVector[i] = info. Is there a more efficient way do that? One that won't involve a copy operation?
This is my current code:
struct CharacterInfo {
QChar character;
int occurrences;
double frequency;
};
std::vector<CharacterInfo> characterInfos;
// Some code to populate the vector
for (unsigned i = 0; i < characterInfos.size(); i++) {
CharacterInfo info = characterInfos[i];
info.frequency = (double)info.occurrences / (double)totalOccurrences;
characterInfos[i] = info; // how to avoid this?
}
The simplest way which doesn't change too much of your code is just to use a reference instead of an instance. So:
SomeStruct & info = myVector[i];
The next easiest way is to change from using a loop with an index, so like:
for (std::vector<SomeStruct>::iterator it = myVector.begin(); it != myVector.end(); ++it)
{
SomeStruct & info = *it;
// do stuff here
}
With the STL you can go even further, especially if you have a C++11 capable compiler, for instance:
std::for_each(std::begin(myVector), std::end(myVector), [](SomeStruct & info) { /* do stuff here */ });
Also not related to your question directly, but if you add a method to the struct that computes the frequency, the code becomes much cleaner, for instance following from the last example you could do:
std::for_each(std::begin(myVector), std::end(myVector), std::mem_fun(&SomeStruct::calculateFrequency));
This will also work without a C++11 compiler if you change the calls to std::begin(myVector) with myVector.begin() and the same for end.
You can use a reference:
CharacterInfo& info = characterInfos[i];
info.frequency = (double)info.occurrences / (double)totalOccurrences;
The reference info is bound to the element of your vector. If you change it, you change
the vector element too.
You could iterate through the vector with an STL iterator:
for (vector<CharacterInfo>::iterator it = characterInfos.begin();
it != characterInfos.end(); ++it) {
it->frequency = (double)it->occurrences / totalOccurrences;
}
In the loop, it is an iterator that has basically same functionality and interface as a pointer to a CharacterInfo struct: http://cplusplus.com/reference/std/iterator/RandomAccessIterator/
Looping with an iterator is the more idiomatic way of iterating through each element of a std::vector if you don't need to know the index of each element.
I am not sure I understand your question but I think you are trying to do this?
for (unsigned i = 0; i < characterInfos.size(); i++) {
characterInfos[i].frequency = (double)characterInfos[i].occurrences / (double)totalOccurrences;
}
Another option would be to use iterators:
for(std::vector<CharacterInfo>::iterator it = characterInfos.begin(); it != characterInfos.end(); ++it){
it->frequency = (double)it->occurences / (double)totalOccurences;
}
Wow, this is a very old question. For "newer" c++, the same can be done with Range-based for loop (since C++11)
for(auto &characterInfo : characterInfos) {
characterInfo.frequency = characterInfo.occurences / static_cast<double>(totalOccurences);
}