function_object lost value of data member after for_each - c++

The following code should store a key and a value. At the end, I want a total sum of all values. But the variable *sum_all* in the my function object sum contains every time "0". What is going on?
// map
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
struct Item {
int count;
double value;
};
class Sum {
public:
Sum() {
sum_all = 0.0;
}
// keys are stored as const in a map
void operator()(pair<const string, Item>& pair) {
cout << pair.first << "\n";
cout << "Sum: " << pair.second.value << "\n";
cout << "Middle: " << pair.second.value/pair.second.count << "\n";
sum_all += pair.second.value;
}
double get_sum_all() {
return sum_all;
}
private:
double sum_all;
};
int main() {
map<string, Item> table;
for (int i = 0; i < 3; i++) {
string key;
double value;
cin >> key;
cin >> value;
// new item
if (table.find(key) == table.end()) {
Item item;
item.count = 1;
item.value = value;
table[key] = item;
} else {
Item& item = table[key];
item.count++;
item.value += value;
}
}
Sum sum;
for_each(table.begin(), table.end(), sum);
cout << "table.size() " << table.size() << "\n";
cout << "sum.get_sum_all() " << sum.get_sum_all() << "\n";
cout << "sum.get_sum_all()/table.size()" << sum.get_sum_all()/table.size() << "\n";
return 0;
}
Example input/output:
[peter#donut chap_6]$ ./u3_map
foo 1
bar 2
foo 1
bar
Sum: 2
Middle: 2
foo
Sum: 2
Middle: 1
table.size() 2
sum.get_sum_all() 0
sum.get_sum_all()/table.size()0
Debugging shows, that sum_all is modified like it should during for_each. But I'm not able to set a watchpoint, or gdb ignores the watchpoint. I thought the constructor is called twice, but this seem not to happen. What I'm doing wrong?
Thanks.

std::for_each takes its functor argument by value, not by reference. The original is not modified. You need to do something like this:
sum = for_each(table.begin(), table.end(), sum);

Related

Iterating over vectors in C++ and erasing certain elements

Just to provide background, I'm trying to write a function in C++ that takes a vector of ints and a particular int, and removes all of the elements of the vector in place that match the particular int, while returning the number of times it appears.
I'm not asking for help solving the problem. I am stuck trying to figure out why the wrong elements are being erased. Here is the code:
int removeElement(vector<int>& nums, int val) {
int output = 0;
int i = 0;
while (i < nums.size()) {
cout << nums[i] << " " << i << " " << (nums[i] == val) << "\n";
if (nums[i] == val) {
nums.erase(nums.begin() + i);
output+=1;
}
else {
i += 1;
}
}
cout << "---------------\n";
return output;
}
Here is what I'm using to test it:
int main() {
vector<int> firstOne = {3,2,2,3};
cout << removeElement(firstOne,2) << "\n";
firstOne = {3,2,2,3};
cout << removeElement(firstOne,3) << "\n";
}
The output is supposed to be {3,3} and then {2,2} but it's {3,3} twice. Not only that, but the whole thing crashes when I try to test it with a vector with only 2 elements. I suspect there is a gap in my understanding of how vectors work. Can anyone explain to me what I'm doing wrong?
It is better to use erase-remove idiom
int removeElement(vector<int>& nums, int val) {
int output = 0;
int i = 0;
// remove if moves elements "to be removed" in the end
auto newend = std::remove_if(nums.begin(), nums.end(), [&](int element){
cout << element << " " << i << " " << (element == val) << "\n";
i++;
if(element == val) {
output++;
return true; // if true, element will be removed
}
return false; // if false, element will not be removed
});
nums.erase(newend, nums.end());
cout << "---------------\n";
return output;
}
Besides the problems suggested in the comments that you just fixed, your code works fine. You are also not updating output anywhere so the function always returns 0 instead of the number of times the int appears in the passed vector. I edited your function a little and it's good to go:
int removeElement(vector<int>& nums, int val) {
int output = 0;
int i = 0;
while (i < nums.size()) {
cout << nums[i] << " " << i << " " << (nums[i] == val) << "\n";
if (nums[i] == val) {
nums.erase(nums.begin() + i);
output++;
}
else {
i += 1;
}
}
cout << "---------------\n";
return output;
}

2D String Array Bubble Sort

I am trying to figure out how to bubble sort a 2D string array. I am currently stuck trying to figure out why my program isnt sorting the strings. I spsupect it could be possible that something is wrong with void swap. I feel somehting with the 2D array needs to be put in there. I am not very sure I just learned how to create bubble sorting algorithms.
#include
using namespace std;
const int SIZE = 2;
const int ROWS = 2;
void bubbleSort(string values[][SIZE]);
void swap(int &, int &);
int main ()
{
string values[ROWS][SIZE] = {{"A23", "A12"}, {"name1", "name2"}};
cout << "Unsorted Values: " << endl;
for(auto element : values)
cout << element << " ";
cout << endl;
cout << "Sorted Values" << endl;
bubbleSort(values);
for (auto element:values)
cout << element << " ";
return 0;
}
void bubbleSort(string values[][SIZE])
{
int maxElement;
int index;
for (maxElement = SIZE - 1; maxElement > 0; maxElement--)
{
for( index = 0; index < maxElement; index++)
{
if (values[0][index] > values[0][index + 1])
{
swap(values[0][index], values[0][index + 1]);
}
}
}
}
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
Your program prints out the adresses because your print loop iterate each entry of your string 2D array. Consequently, every entry is an array. So arr holds the pointer to the first element of the array.
You only need a nested loop to print out the values of the single elements:
for (auto row : values)
for (int i = 0; i < SIZE; i++)
std::cout << row[i] << " ";
Furthermore, there is no need to implement an own swap function. Just use std::swap(T&,T&)
But i assume that you want to achieve a multi array sort. Then you should use a simple struct to represent an entity instead of multiple arrays and implement a operator to compare two entities. I suggest to use a range based container too. Then you can take advantage of the standard sort functions.
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Entry
{
string id;
string name;
bool operator<(const Entry& comp)
{
return id < comp.id;
}
};
int main()
{
auto print = [](const vector<Entry>& vec)
{
for (auto& el : vec)
{
cout << el.id << "->" << el.name << "\t";
}
};
vector<Entry> values { {"A23","name1" }, {"A12", "name2"} };
cout << "Unsorted Values: " << endl;
print(values);
cout << endl;
std::sort(values.begin(), values.end());
cout << "Sorted Values" << endl;
print(values);
return 0;
}
Prints out:
Unsorted Values:
A23->name1 A12->name2
Sorted Values:
A12->name2 A23->name1

c++ vector of structs inside class

hello all i am working on a school prject called inventory inquisitor. the specifications are as follows:
enter image description here
so far i have created a class in which contains a struct and a vector of this struct.
all im trying to do so far is get the class to display the struct just to know it works but when i compile it and run it nothing happens. here is the code. excuse whatever rookie mistakes i have made i am very new with classes, and vectors. thanks you in advance!
//Inventory Inquisitor.cpp
#include <iostream>
#include <string>
#include <cctype> //for toupper
#include <fstream>
#include <vector>
using namespace std;
class Inventory
{
private:
struct item
{
string Description = " ";
double Quantity = 0;
double Wholesalescost = 0;
double Retailcost = 0;
string Dateadded = " ";
};
vector<item> Inv;
public:
void Display();
};
void Inventory::Display()
{
Inv[0].Description = "english";
Inv[0].Quantity = 1;
Inv[0].Wholesalescost = 100;
Inv[0].Retailcost = 200;
Inv[0].Dateadded = "3/8/2018";
cout << Inv[0].Description << endl;
cout << Inv[0].Quantity << endl;
cout << Inv[0].Wholesalescost << endl;
cout << Inv[0].Retailcost << endl;
cout << Inv[0].Dateadded << endl;
}
int main()
{
Inventory inst1;
inst1.Display();
}
You have to put something into the vector before accessing it:
// Create an item
item i;
i.Description = "english";
i.Quantity = 1;
i.Wholesalescost = 100;
i.Retailcost = 200;
i.Dateadded = 3/8/2018;
// The vector is empty, size() == 0
// Add it to the vector
Inv.push_back(i);
// Now the vector has 1 item, size() == 1
// Now you can print it
cout << Inv.at(0).Description << endl;
cout << Inv.at(0).Quantity << endl;
cout << Inv.at(0).Wholesalescost << endl;
cout << Inv.at(0).Retailcost << endl;
cout << Inv.at(0).Dateadded << endl;
According to your assignment, you will most likely change to function to print an existing item. You will have another function to add items to the vector.
void Inventory::Display(int index)
{
// Print an item already in the vector
if (index >= 0 && index < Inv.size()) {
cout << Inv.at(index).Description << endl;
cout << Inv.at(index).Quantity << endl;
cout << Inv.at(index).Wholesalescost << endl;
cout << Inv.at(index).Retailcost << endl;
cout << Inv.at(index).Dateadded << endl;
}
}

simplify my code in C++ below

I want to create a program which is able to calculate the surface area, volume, and circumference. for your additional info, I am studying about function, I has just learned about C++ about a week.
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
int getPostP(string msgP)
{
int Ppost= 0.000;
do
{
cout << msgP << endl;
cin >> Ppost;
return Ppost;
} while(Ppost<= 0);
}
int getPostL(string msgL)
{
int Lpost= 0.000;
do
{
cout << msgL << endl;
cin >> Lpost;
return Lpost;
} while(Lpost<= 0);
}
int getPostT(string msgT)
{
int Tpost = 0.000;
do
{
cout << msgT << endl;
cin >> Tpost;
return Tpost;
} while(Tpost <= 0);
}
int surfaceArea(int Psur, int Lsur, int Tsur)
{
return (2*Psur*Lsur)+(2*Psur*Tsur)+(2*Lsur*Tsur);
}
int volume(int Pvol, int Lvol, int Tvol)
{
return (Pvol*Lvol*Tvol);
}
float circumference(int Pcir, int Lcir, int Tcir)
{
return 4*(Pcir+Lcir+Tcir);
}
int main()
{
int P = getPostP("enter the P of your block");
int L = getPostL("enter the L of your block");
int T = getPostT("enter the T of your block");
float surfAreaBlock = surfaceArea(P, L, T);
float volBlock = volume(P, L, T);
float cirBlock = circumference(P, L, T);
cout << "block which have P = " << P << " and L = " << L << " and T = "<< T << " have surface area = " <<
surfAreaBlock << " and volume = " << volBlock << " and cirBlock = " << cirBlock;
return 0;
}
Maybe one of you want to rewrite and add some comment, which parts are able to simplify, so I can understand easier.
First of all, it looks like you should make all of your integer inputs into double instead of int, since it's expected that your inputs won't necessarily be an exact integer amount (probably). Also you can get rid of all of your duplicate functions for entering the parameters. Change it to a single function and call that one for each variable.
double getInput(const std::string& prompt)
{
double input(0.0);
do
{
std::cout << prompt << "\n-> " << std::flush;
// forces input to be a double type
while (!(std::cin >> input))
{
std::cout << "\n-> " << std::flush;
std::cin.clear();
std::cin.ignore(256, '\n'); ///< could use streamsize::max here
}
} while (input <= 0.0); ///< make sure it's positive
return input;
}

c++ Sharing list between main an exterior function

I am making a rabbit population simulator for a challenge I am doing. I have a map of class objects. I also have a list which contains the keys for the map. Each round of the simulator I want to add more objects to the class, and update my map and list. To do this I wrote a separate "creation" function which will randomly generate new class objects and add them to a map and add the keys to a list.
The problem is when I call the creation function, then iterate through the map using the list it shows the map or list is empty (not sure which). If I iterate through the map before leaving the function it only shows the newest objects. If I move the code for the function into the main function, it works correctly (calling it twice gives me the new objects created in the first iteration of the code, and also the objects created by the second iteration).
I am guessing that a new list or map is being created each time the function is called and is overwriting the old list or map. How can I get the list and map to pass between the main function and the creation function?
Here is my code:
#include "stdafx.h"
#include <iostream>
#include "windows.h"
#include <string>
#include <sstream>
#include <array>
#include <time.h>
#include <conio.h>
#include <map>
#include <list>
class Bunny
{
public:
char fname;
int sex, age, color, status;
Bunny(int, int, int, int);
Bunny();
int s() { return (sex); }
int a() { return (age); }
int c() { return(color);}
int st() { return (status);}
int aging(int age) { return (age + 1); }
};
Bunny::Bunny(int s, int a, int c, int st)
{
sex = s;
age = a;
color = c;
status = st;
}
Bunny::Bunny(){}
void creation(std::map<std::string, Bunny> bunnies, std::list<std::string>names, int births);
std::string firstname(int s, int num)
{
std::string name;
if (s == 0)
{
switch (num)
{
case (0) :
name = "Tim";
break;
case (1) :
name = "Tom";
break;
case (2) :
name = "Mark";
break;
case (3) :
name = "Bob";
break;
case (4) :
name = "Rob";
break;
}
}
if (s == 1)
{
switch (num)
{
case (0) :
name = "Suzy";
break;
case (1) :
name = "Linda";
break;
case (2) :
name = "Mary";
break;
case (3) :
name = "Jan";
break;
case (4) :
name = "Julie";
break;
}
}
return (name);
}
void main()
{
int num = rand() % 5;
int n, births = 10;
std::list<std::string>names;
std::map<std::string, Bunny> bunnies;
srand(time(0));
creation(bunnies, names, births);
std::cout << "Number" << "\t" << "Name" << "\t" << "age" << "\t" << "Sex" << "\t" << "Color" << "\t" << "Vampire?" "\n";
n = 0;
for (std::list<std::string>::iterator it = names.begin(); it != names.end(); it++)
{
n++;
std::cout << n << "\t";
std::cout << " " << *it;
std::cout << "\t" << bunnies[*it].a() << "\t" << bunnies[*it].s() << "\t" << bunnies[*it].c() << "\t" << bunnies[*it].st() << "\n";
}
creation(bunnies, names, births);
_getch();
}
/*void year()
{
for (std::list<std::string>::iterator it = names.begin(); it != names.end(); it++)
{
bunnies[*it].aging(bunnies[*it].a())
}
}*/
void creation(std::map<std::string, Bunny> bunnies,std::list<std::string> names,int births)
{
int n;
for (n = 0; n < births; n++)
{
int num = std::rand() % 5;
char id = (std::rand() % 100) + 20;
int s = std::rand() % 2;
std::string f = firstname(s, num) + '_' + id;
int a = 0;
int c = std::rand() % 5;
int st;
if (rand() % 50 == 43) st = 1; else st = 0;
bunnies[f] = Bunny(s, a, c, st);
names.push_front(f);
//std::cout << f << " " << bunnies[f].a() << " " << bunnies[f].c() << "\n";
}
std::cout << "Number" << "\t" << "Name" << "\t" << "age" << "\t" << "Sex" << "\t" << "Color" << "\t" << "Vampire?" "\n";
n = 0;
for (std::list<std::string>::iterator it = names.begin(); it != names.end(); it++)
{
n++;
std::cout << n << "\t";
std::cout << *it;
std::cout << "\t" << bunnies[*it].a() << "\t" << bunnies[*it].s() << "\t" << bunnies[*it].c() << "\t" << bunnies[*it].st() << "\n";
}
}
Your problem is that your main function is passing your map and list by value instead of passing by reference. This means that your creation function is receiving a copy of the existing map/list, rather than a reference to the original one you created. Since it is then only making edits to that copy, any changes it makes will not be reflected in the main function.
Change your creation function from:
void creation(std::map<std::string, Bunny> bunnies, std::list<std::string>names, int births)
to
void creation(std::map<std::string, Bunny>& bunnies, std::list<std::string>& names, int births)