Clearing vectors and letting one vector equal another - c++

Right I have two vectors. I want to empty the vector(list) and replace its contents with the contents of the other vector(templist) and clear templist when I've done that. Is this the right code?
list.clear();
list = templist;
templist.clear();

That is what the swap method is for:
list.swap(templist); // The contents are swapped
templist.clear(); // Clear the one you don't need anymore
Note that this is faster than list = templist because the contents are not copied.

All you need is this:
list = templist;
templist.clear();

Related

Moving object to front of vector pair string c++

I have a question about moving an Object to the front in a vector pair. I already read that one post but I didnt know how to use it with vector pairs or better said how to do it with strings. I dont know how to point with an iterator at the position I need because in my code I also need a count number to compare the two strings or how is it possible to compare something like if(it==ite){..} (i would need 2 loops for my examples so I would name the other one "ite" just as an example.
I have a vector<pair<string,string>> Dictionary and a vector string Text where I go through the dictionary and try to find the same word from the text in the dictionary. I already accomplished that but now I need to move the element that I found in the dictionary to the front and delete it from its old position.
I´m not sure how to do it with vector pairs.
Here´s my code to understand what I mean:
for(size_t i=0;i<Text.size();i++){
for(size_t j=0;j<Duden.size();j++){
if(Text[i]==Duden[j].first){
uebersetzung.push_back(Duden[j].first);
if(Duden[j].first.length()<4){
uebersetzung.push_back(" ");}
if(Duden[j].first.length()<8){
uebersetzung.push_back("\t");} // These are only so it looks cleaner at the end
uebersetzung.push_back("\t\t\t\t: ");
uebersetzung.push_back(Duden[j].second);
uebersetzung.push_back("\n");
// Now here should be the code to rotate the vector so the found element is now at the first position and not at the found position
break;
}
}
}
"Duden" here is dictionary if you´re wondering. I want to swap position of the elements from the dictionary so if the word occurs again in the text it doesnt need to go trough the whole dictionary again and instead just find it directly in the first positions.
How can I accomplish that with using rotate? Or do I need to do it with erase and insert because rotate doesnt work with pairs of vectors?
Consider making use of algorithms in the STL library. To use them, you have to get familiar with iterators. Then you can use something like std::rotate and it does not really matter what is in your vector.
For example your code can be refactored in the following way:
for (auto const& word : Text) {
auto it = std::find(Duden.begin(), Duden.end(), [&word](auto const& entry) {
return entry.first == word;
});
if(it == Duden.end()) {
continue;
}
generate_translation(uebersetzung, *it);
std::rotate(Duden.begin(), it, it+1);
}
The function generate_translation(std::vector<string>&, std::pair<string, string> const&) should be an own function to make the code more readable.
Something like
void generate_translation(std::vector<string>& uebersetzung,
std::pair<string, string> const& entry)
{
uebersetzung.push_back(entry.first);
if(entry.first.length() < 4){
uebersetzung.push_back(" ");
}
if(entry.first.length() < 8){
uebersetzung.push_back("\t");
} // These are only so it looks cleaner at the end
uebersetzung.push_back("\t\t\t\t: ");
uebersetzung.push_back(entry.second);
uebersetzung.push_back("\n");
}

Segmentation fault during erasing from vector

I'm developing an Asteroid game clone but I'm facing a problem during erasing elements from vector of asteroids. So generally when I hit the asteroid it should split into 3 parts. So I create 3 new asteroids and erase the old one an then it crashes.
void Level::missleAsteroidCollision(){
std::cout<<this->asteroidVector.size()<<std::endl;
for(auto ptr = this->missleVector.begin();ptr!=this->missleVector.end();++ptr){
sf::FloatRect missleBounds = (*ptr)->shape.getGlobalBounds();
for(auto ptrTwo = this->asteroidVector.begin(); ptrTwo!= this->asteroidVector.end();++ptrTwo){
if(missleBounds.intersects((*ptrTwo)->shape.getBounds()) && (*ptrTwo)->isFinalForm == false){
for(int i = 0; i < 3; ++i){
this->createAsteroid((*ptrTwo)->origin,true);
}
delete *ptrTwo;
this->asteroidVector.erase(ptrTwo);
}
else if(missleBounds.intersects((*ptrTwo)->shape.getBounds()) && (*ptrTwo)->isFinalForm == true){
delete *ptrTwo;
this->asteroidVector.erase(ptrTwo);
}
}
}
}
First of all, when you use the .erease function, the iterator is changed so you need to update it, in your case, ptr = this->asteroidVector.erase(ptrTwo); the iterator will now point to the next element after deletion so keep that in mind (either you decrease the pointer by one or you only increase the ptr (ptr++) if you did not use the .erase function.
Secondly, I believe this->createAsteroid((*ptrTwo)->origin,true); creates new items, this will also invalidate the iterator, so one fix could be, creating the new asteroids after checking and deleting the old one. Maybe store the new asteroids in a vector created before the for loop, adding the new meteorites there and after the for loop add the vector to your current vector of asteroids.
Inserting an item into a vector (whether or not at the end of the vector) can invalidate all iterators to that vector. I suspect your createAsteroid does so.

Deleting an element from an array of objects

I tried to write a function that gets an object ("Stone") and deletes the stone from a given array. code:
void Pile::del_stone(Stone &s)
{
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i <size;++i)
{
if (s != Pile_arr[i])//if the given object to delete is different from the current
{
temp[i] = Pile_arr[i];//copy to the new array
}
else
{
i--;
}
}
Pile_arr = temp;
set_size(this->size - 1);
temp = NULL;
delete[] temp;
}
Pile_arr is a member of Pile class.
The problem is that i get an infinite loop, because i decrease i. I cant figure out how to solve this issue. Any ideas?
Use two indexes: i and j. Use i to know which element of the original array you are looking and j to know where to put the element in temp.
You need to use a separate counter to track where new elements should be placed.
I have used n below:
Stone *temp = new Stone[size - 1];
int n = 0; // Stores the current size of temp array
for (int i = 0;i <size;++i) {
if (s != Pile_arr[i]) {
temp[n++] = Pile_arr[i];
}
}
It's also worth considering the case where s is not found in the array, as this would cause a runtime error (Attempting to add size elements to an array of size size - 1).
Using a STL container would be a far better option here.
This function will:
Allocate a new array of length size-1
Search for the intended object
If you find it, copy it to the same exact position in the array
If you don't --i
Finally, ++i
First of all, this function is bad for 3 reasons:
It only copies one item over--the given item. You have an array with only 1 object.
It copies the item from index to index. Since the final array is one smaller, if the object is at the max original index, it will be out of bounds for the new array.
If the object is not immediately found, the array will get stuck, as you decrease the index, and then increase it using the loop--you'll never move again.
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i
Instead:
Cache the found object, then delete it from the original array or mark it. temp = found object
Copy the array, one by one, without copying empty spaces and closing the gap. Copy temp_array[i] and increment i if and only if temp_array[j] is not marked/deleted. Increment j
Decide where to put the found object.
Once again, you can decide to use separate indexes--one for parsing the original array, and one for filling the new array.

How to iterate through a list while adding items to it

I have a list of line segments (a std::vector<std::pair<int, int> > that I'd like to iterate through and subdivide. The algorithm would be, in psuedocode:
for segment in vectorOfSegments:
firstPoint = segment.first;
secondPoint = segment.second;
newMidPoint = (firstPoint + secondPoint) / 2.0
vectorOfSegments.remove(segment);
vectorOfSegments.push_back(std::make_pair(firstPoint, newMidPoint));
vectorOfSegments.push_back(std::make_pair(newMidPoint, secondPoint));
The issue that I'm running into is how I can push_back new elements (and remove the old elements) without iterating over this list forever.
It seems like the best approach may be to make a copy of this vector first, and use the copy as a reference, clear() the original vector, and then push_back the new elements to the recently emptied vector.
Is there a better approach to this?
It seems like the best approach may be to make a copy of this vector first, and use the copy as a reference, clear() the original vector, and then push_back the new elements to the recently emptied vector.
Almost. You don't need to copy-and-clear; move instead!
// Move data from `vectorOfSegments` into new vector `original`.
// This is an O(1) operation that more than likely just swaps
// two pointers.
std::vector<std::pair<int, int>> original{std::move(vectorOfSegments)};
// Original vector is now in "a valid but unspecified state".
// Let's run `clear()` to get it into a specified state, BUT
// all its elements have already been moved! So this should be
// extremely cheap if not a no-op.
vectorOfSegments.clear();
// We expect twice as many elements to be added to `vectorOfSegments`
// as it had before. Let's reserve some space for them to get
// optimal behaviour.
vectorOfSegments.reserve(original.size() * 2);
// Now iterate over `original`, adding to `vectorOfSegments`...
Don't remove elements while you insert new segments. Then, when finished with inserting you could remove the originals:
int len=vectorOfSegments.size();
for (int i=0; i<len;i++)
{
std::pair<int,int>& segment = vectorOfSegments[i];
int firstPoint = segment.first;
int secondPoint = segment.second;
int newMidPoint = (firstPoint + secondPoint) / 2;
vectorOfSegments.push_back(std::make_pair(firstPoint, newMidPoint));
vectorOfSegments.push_back(std::make_pair(newMidPoint, secondPoint));
}
vectorOfSegments.erase(vectorOfSegments.begin(),vectorOfSegments.begin()+len);
Or, if you want to replace one segment by two new segments in one pass, you could use iterators like here:
for (auto it=vectorOfSegments.begin(); it != vectorOfSegments.end(); ++it)
{
std::pair<int,int>& segment = *it;
int firstPoint = segment.first;
int secondPoint = segment.second;
int newMidPoint = (firstPoint + secondPoint) / 2;
it = vectorOfSegments.erase(it);
it = vectorOfSegments.insert(it, std::make_pair(firstPoint, newMidPoint));
it = vectorOfSegments.insert(it+1, std::make_pair(newMidPoint, secondPoint));
}
As Lightning Racis in Orbit pointed out, you should do a reserve before either of these approaches. In the first case do reserve(vectorOfSegmets.size()*3), in the latter reserve(vectorOfSegmets.size()*2+1)
This is easiest solved by using an explicit index variable like this:
for(size_t i = 0; i < segments.size(); i++) {
... //other code
if(/*condition when to split segments*/) {
Point midpoint = ...;
segments[i] = Segment(..., midpoint); //replace the segment by the first subsegment
segments.emplace_back(Segment(midpoint, ...)); //add the second subsegment to the end of the vector
i--; //reconsider the first subsegment
}
}
Notes:
segments.size() is called in each iteration of the loop, so we really reconsider all appended segments.
The explicit index means that the std::vector<> is free to reallocate in the emplace_back() call, there are no iterators/pointers/references that can become invalid.
I assumed that you don't care about the order of your vector because you add the new segments to the end of the vector. If you do care, you might want to use a linked list to avoid quadratic complexity of your algorithm as insertion/deletion to/from an std::vector<> has linear complexity. In my code I avoid insertion/deletion by replacing the old segment.
Another approach to retain order would be to ignore order at first and then reestablish order via sorting. Assuming a good sorting algorithm, that is O(n*log(n)) which is still better than the naive O(n^2) but worse than the O(n) of the linked list approach.
If you don't want to reconsider the new segments, just use a constant size and omit the counter decrement:
size_t count = segments.size();
for(size_t i = 0; i < count; i++) {
... //other code
if(/*condition when to split segments*/) {
Point midpoint = ...;
segments[i] = Segment(..., midpoint); //replace the segment by the first subsegment
segments.emplace_back(Segment(midpoint, ...)); //add the second subsegment to the end of the vector
}
}

How to extract an element from a deque?

Given the following code :
void World::extractStates(deque<string> myDeque)
{
unsigned int i = 0;
string current; // current extracted string
while (i < myDeque.size()) // run on the entire vector and extract all the elements
{
current = myDeque.pop_front(); // doesn't work
// do more stuff
}
}
I want to extract each iteration the element at the front , but pop_front() is a void
method . How can I get the element (at the front) then ?
Regards
Use front to read the item and pop_front to remove it.
current = myDeque.front();
myDeque.pop_front();
This way of doing things may seem counter-productive, but it is necessary in order for deque to provide adequate exception-safety guarantees.