I have a vector of Structs that represent points (allPoints). This vector contains the entire collection of points on a given plane (in this example it contains four points). Each struct contains a pair of integers representing a point, a flag, as well as another vector of points which contains every other point on the plane.
What I want to do is select a point from the preference list of a point, change its flag, and have this change apply to the point in the allPoints vector. I imagine I need a vector of references or something similar. Here is an example of what I am talking about:
#include <iostream>
#include <string>
#include <vector>
#include <utility>
using namespace std;
struct Point {
pair<int,int> p;
vector<Point> prefs;
bool flag = true;
};
void fillVectors(vector<Point> & allPoints);
void printState(vector<Point> & allPoints);
int main()
{
vector<Point> allPoints;
fillVectors(allPoints);
printState(allPoints);
// I want to go into the preference list of any given point, select a point, and change its flag. This change
// should be reflected in the allPoints vector, not just the preferences vector
allPoints[0].prefs[2].flag = false;
printState(allPoints);
// The flags have not changed. If I searh for the point in allPoints, then change the flag, it will change
for(Point p : allPoints)
{
if(p.p == allPoints[0].prefs[2].p) allPoints[0].flag = false;
}
printState(allPoints);
}
void fillVectors(vector<Point> & allPoints)
{
pair<int,int> p1 = make_pair(0,0);
pair<int,int> p2 = make_pair(5,0);
pair<int,int> p3 = make_pair(3,7);
pair<int,int> p4 = make_pair(2,9);
vector<pair<int,int>> coords = {p1, p2, p3, p4};
for(int i = 0; i < coords.size(); i++)
{
Point newPoint;
newPoint.p = coords[i];
allPoints.push_back(newPoint);
}
// Fill the preference lists with every other point (in no particular order)
for(int i = 0; i < allPoints.size(); i++)
{
for(int j = 0; j < allPoints.size(); j++)
{
if(i == j) continue; // Do not put a point in its own preference list
allPoints[i].prefs.push_back(allPoints[j]);
}
}
}
void printState(vector<Point> & allPoints)
{
cout << "Contents of all points:\n";
for(Point p : allPoints)
cout << "point: (" << p.p.first << "," << p.p.second << ")" << " Flagged? -> " << p.flag << "\n";
cout << "~\nContents of each preference vector:\n";
for(Point p : allPoints)
{
cout << "point: (" << p.p.first << "," << p.p.second << ")\tprefs: ";
for(Point q : p.prefs)
cout << "(" << q.p.first << "," << q.p.second << "), ";
cout << "\n";
}
cout << "--------------------\n";
}
Here, I have allPoints which holds four pairs. The print state function prints every point from the all points along with its flag, then the preference list of each point. What I need is for the prefs vector in each point to hold references to that point object in the allPoints vector. Instead, it just seems to be making a copy.
I want do to this so that I can change point flags in O(1) time, rather than the O(n) time it takes to get the point from the preferences, then search for it in allPoints and change it
If the only part of state which you want to be shared is flag and if you do not plan to change value of Point::p member once object created, you can replace bool flag with std::shared_ptr<bool> flag and when copies are created - shared_ptr will be copied and it will hold the value shared between objects.
struct Point
{
Point(const std::pair<int,int>& value)
: p(value)
{}
Point(const Point&) = default;
Point& operator = (const Point&) = default;
const std::pair<int,int> p;
vector<Point> prefs;
std::shared_ptr<bool> flag = std::make_shared<bool>(true);
};
Then if you will do:
Point pt1({1,2});
auto pt2 = pt1;
std::cout << *pt2.flag << " ";
*pt1.flag = false;
std::cout << *pt2.flag << " ";
the output will be "1 0" since pt1 and pt2 objects share same bool.
Note: if there is no const for Point::p then it's possible to change it's value after copies from object are created - in this case sharing flag for such objects makes no sense.
Of course, that would be easy to break given all members are public, so you'll need to access flag carefully. To make this code safe - encapsulation should be used.
Related
So I know to print something in a loop, the code looks like this:
for(int I = 0; I < num; ++I)...
And to print an object vector:
for(Square sq : squares)...
(if I have a class Square and I create the object sq and squares is the name of the vector)
But how would I go about code if I want my output to look like:
square 1 area: 3
square 2 area: 6
square 3 area: 9
To be more clear: my question is, how do I incorporate "I" like in the first example in a loop where I'm printing objects?
You can do it like this:
for (size_t idx=0; idx<squares.size(); ++idx)
{
Square const & sq = squares[idx];
// Here you can use both:
// idx (which is the index in the vector),
// and sq (reference to the element).
}
The fact that sq is a std::vector does not mean you must traverse it using the range-based loop (Range-based for loop).
A std::vector has a method for getting its size (std::vector::size), and operator[] to access an element (std::vector::operator[]).
Note - even if you do use the range-based loop, it is better to use a refernce (or const reference) to avoid unnecessary copies:
for(Square const & sq : squares) // without `const` if you need to modify the element
{
//...
}
You can also combine range based for and another index variable
// with c++20 range-based for can have initializer in it
for(auto i=1; auto& s:squares){
std::cout << "square " << i << " area: " << s << '\n' ;
++i;
}
https://godbolt.org/z/EfhefdoGP
pre-c++20
{
auto i=1;
for(auto& s:squares){
std::cout << "square " << i << " area: " << s << '\n' ;
++i;
}
}
Because the elements of the vector are lined up continuously... It may be possible to do something like this.
class Object
{
public:
Object( int a, int b ) : a(a),b(b) {}
int a,b;
};
int main()
{
std::vector<Object> Vec{ {1,2}, {10,20}, {100,200} };
for( const auto &obj : Vec )
{
auto index = &obj - &Vec[0]; //calculate index of element
std::cout << index << " : " << obj.a << "," << obj.b << std::endl;
}
return 0;
}
I was trying to sort the areas of a circle in an ascending order. First, the user chooses the number of circles, then he should type the coordinates and the area of his circles. In the end the program should output the radius of a circle in an ascending order.But the output of areas is not in an ascending order(It's the same as input). What is my problem?
#include<iostream>
#include <algorithm>
using namespace std;
struct circle {
int 반지름;
int coordinates;
int coordinates2;
};
bool compare(circle a, circle b){
if(a.반지름 < b.반지름)
return 1;
else
return 0;
}
int main()
{
int n = 1;
int* ptr1;
ptr1 = new int;
circle* circle1;
circle1 = new (nothrow) circle[5];
circle1[0].반지름;
circle1[0].coordinates;
circle1[0].coordinates2;
circle1[1].반지름;
circle1[1].coordinates;
circle1[1].coordinates2;
circle1[2].반지름;
circle1[2].coordinates;
circle1[2].coordinates2;
circle1[3].반지름;
circle1[3].coordinates;
circle1[3].coordinates2;
circle1[4].반지름;
circle1[4].coordinates;
circle1[4].coordinates2;
circle1[5].반지름;
circle1[5].coordinates;
circle1[5].coordinates2;
cout << "Enter the number of circles: ";
cin >> *ptr1;
cout << "중심 좌표, 반지름 : " << endl;
for (int i = 0; i < *ptr1; i++) {
cin >> circle1[i].coordinates >> circle1[i].coordinates2 >> circle1[i].반지름;
}
sort(circle1, circle1 + 1, compare);
for (int i = 0; i < *ptr1; i++) {
cout << "The result: " << circle1[i].coordinates << " " << circle1[i].coordinates2 << " " << circle1[i].반지름 << endl;
}
delete[] circle1;
delete ptr1;
return 0;
}
That's not C++, that's a strange and hybrid thing between C and C++... And this is your main problem. You're mixing up things that should not be mixed, not if you don't know PERFECLY what you do - and obviously, it's not the case, otherwise your code should have worked, and it haven't.
Corrected code, in real C++:
#include <iostream> // std::cout & co
#include <algorithm> // std::sort
#include <cstdlib> // std::rand & co
#include <vector> // std::vector
struct circle {
int area ;
int x ;
int y ;
} ;
// For printing a circle easily and not repeat code X times.
// Print as: [area#(x,y)]
std::ostream& operator<<(std::ostream& os, const circle& c) {
os << "[" << c.area << "#(" << c.x << "," << c.y << ")]" ;
return os;
}
int main() {
// Set a constant seed: each run will produce the same result, if needed to debug.
std::srand(1234) ;
// 5 circles declared within a vector, not a C array.
auto circles = std::vector<circle>(5) ;
// Fill the vector.
std::cout << "Original circles:" << std::endl ;
// Use a simpler for syntax.
for ( auto& c: circles ) {
// Random values used. The fixed seed will always give the same values on each run.
c.area = 10 + std::rand() % 50 ;
c.x = std::rand() % 1920 ;
c.y = std::rand() % 1080 ;
// Print the circle.
std::cout << "\t" << c << std::endl ;
}
// Sort the vector, use a lambda expression for the compare operator.
// No need for a "real" function, if it's used only once and only there.
// Compare function returns directly a bool, not an integer.
std::sort(circles.begin(), circles.end(), [](const circle& a, const circle& b) -> bool { return (a.area<b.area) ; });
// Display sorted vector.
std::cout << std::endl << "Sorted circles:" << std::endl ;
for ( const auto& c: circles )
std::cout << "\t" << c << std::endl ;
return 0;
}
Still strange that you use area instead of radius or diameter, but anyway... Area is for a disc, not a circle, but that's mathematical precision at this stage.
First, if you print a structure like circle at least twice, do a stream operator to do it only once. Please note that I send directly the structure to std::cout, after...
Then, I use a C++ container, not a C allocated array. You can still allocate memory for big amount of data, but for this example, that's unneeded.
Then, instead of asking for each values, I use std::rand() to fill them. Easier. Can be used in any language. Refined trick: I initialize the pseudo-random generator to a constant, fixed value, so each time the program is run, it will generate the exact same sequence of pseudo-random numbers - this can vary on each machine / OS / compiler / compiler version but it will be constant on YOUR machine during your tests, and it can be debugged easily.
Please also note that I use a compact form of for that will iterate on the whole circles container, giving me each time a circle& (reference) on each element so that I can modify it - needed for initialization.
Now, the sort itself: from begin() to end() of the container, using a lambda expression to define the compare operator. Please note that I return directly the result of the comparison, which is a bool, and that I don't cast an int to a bool implicitely...
Finally, print the result. Note that this time, I ask for a const auto& reference, to be sure to not modify data by mistake.
Nothing to delete, C++ will take care of that.
An example output, on my machine:
Original circles:
[28#(213,881)]
[18#(16,157)]
[34#(1468,816)]
[14#(745,718)]
[31#(143,818)]
Sorted circles:
[14#(745,718)]
[18#(16,157)]
[28#(213,881)]
[31#(143,818)]
[34#(1468,816)]
I'm trying to use an unordered_map for a custom type. However, the map is storing duplicate entries, which have the same hash value and should evaluate as equal when using ==.
I've reduced my code to the following proof of concept, where I can see that the hash function runs correctly, but the equals operator is never called.
#include <unordered_map>
// Define a class with a single integer member.
class Example
{
public: int x;
public: Example(int x)
{
this->x = x;
}
// Overload == and compare the single member.
public: bool operator==(const Example &other) const
{
std::cout << "Comparing two objects\n";
return this->x == other.x;
}
};
// Define a hash function class
class ExampleHash
{
public: size_t operator()(const Example* key) const
{
// simply return the member variable as the hash value.
std::cout << "Returning hash value " << key->x << "\n";
return key->x;
}
};
int main()
{
// Create an empty map.
std::unordered_map<Example*, int, ExampleHash> m;
std::cout << "Inserting a new key\n";
// Insert an object with the value 1.
m[new Example(1)] = 1;
std::cout << "Existing hashes:\n";
ExampleHash fn;
for (auto const &item : m) {
size_t h = fn(item.first);
std::cout << " " << h << ", ";
}
std::cout << "\n";
std::cout << "Finding the key\n";
// Check if the object is in the map.
std::cout << ((m.find(new Example(1)) != m.end()) ? "Found" : "Not found") << "\n";
}
Output:
Inserting a new key
Returning hash value 1
Existing hashes:
Returning hash value 1
1,
Finding the key
Returning hash value 1
Not found
(Note the absence of the "Comparing two objects" line when calling unordered_map::find, despite the hash value clearly being in the map already.)
Pointers are not the objects they point to.
You are using pointers as keys. The objects equal operator will be ignored.
I'm trying to build a relational database for the class I'm in.
what's happening is that when I process my "Facts" and "Queries" input, I create a new relation object. And then I print them out. If I run one at a time they process just fine, but if I run them back to back, the second one modifies the contents of the vector of tokens within the other relation object.
Database.h
class Database
{
private:
datalogProgram program;
Relation theSchemes;
Relation theFacts;
std::vector<Token> FactsOrder;
public:
Database(datalogProgram input);
Database();
~Database();
Relation processSchemes(datalogProgram processme);
Relation processFacts(datalogProgram processme);
};
Database.cpp
And I apologize for all of the cout's I've been trying to debug this things for hours!
#include "Database.h"
#include <sstream>
Database :: Database(datalogProgram input)
{
// So first I will make a map with relations representing the Schemes Facts and Queries
// Thus I will have a database of schemes facts and queries, rules excluded and ignored for now.
program = input;
theSchemes = processSchemes(program);
theFacts = processFacts(program);
// just checking on progress.
std::cout << "SCHEMES" << std::endl;
theSchemes.printRelation();
std::cout << "FACTS" << std::endl;
theFacts.printRelation();
}
Database :: Database() {}
Database :: ~Database() {}
Relation Database :: processSchemes(datalogProgram input)
{
Relation temp;
// LETS START WITH SCHEMES
std::cout << "processing schemes" << std::endl;
std::vector<Scheme>* schemes = input.returnSchemeList();
// Process First Scheme
// Populate this first vector with ID's from schemes.
// std::vector<Token*> firstTuple;
std::vector<Token*> firstTuple;
std::vector<Token> idListONE;
firstTuple.push_back(input.returnFirstScheme()->returnFirstID());
// std::vector<Token> idListONE;
idListONE = input.returnFirstScheme()->returnCLEANidLIST();
for(int i = 0; i < input.returnFirstScheme()->returnCLEANidLIST().size(); i++)
firstTuple.push_back(&idListONE[i]);
temp = *new Relation(input.returnFirstScheme()->returnName(), firstTuple);
// NOW I NEED TO PROCESS THE REST OF THE SCHEMES
//Take a scheme off of the list, and work on it just like I did above.
for(int j = 0; j < schemes->size(); j++) {
// Populate this first vector with ID's from schemes.
std::vector<Token*> first;
first.clear();
first.push_back(schemes->at(j).returnFirstID());
std::vector<Token> idLista;
idLista.clear();
idLista = schemes->at(j).returnCLEANidLIST();
for(int i = 0; i < schemes->at(j).returnCLEANidLIST().size(); i++)
first.push_back(&idLista[i]);
temp.relationInsert(schemes->at(j).returnName(), first);
}
return temp;
//
// At this point I shoudl have a map with "Schemes" pointing to Relation Objects.
// I want to verify that this is working, so print out all data collected so far.
}
Relation Database :: processFacts(datalogProgram input)
{
Relation temporary;
// NOW WE PROCESS FACTS
// Order does matter, so I will create a vector to use as a key.
std::cout << "procesing facts" << std::endl;
std::vector<Fact>* facts = input.returnFactList();
std::string OUT2;
std::ostringstream convert2;
convert2 << facts->size();
OUT2 = convert2.str();
std::cout << "THE NUMBER OF FACTS IS " << OUT2 << std::endl;
// NOW I NEED TO PROCESS THE REST OF THE
//Take a scheme off of the list, and work on it just like I did above.
std::vector<Token*> firstTuple;
std::vector<Token> idListONE;
for(int j = 0; j < facts->size(); j++) {
std::cout << "NEW ITERATION:" << std::endl;
if(j==0) {
std::cout << "processing first fact" << std::endl;
// is the first Fact!
firstTuple.clear();
std::cout << "processing first fact --> tuple" << std::endl;
firstTuple.push_back(facts->at(j).returnFirstString());
idListONE.clear();
std::cout << "FIRST STRINGLIST" << std::endl;
idListONE = *facts->at(j).returnCleanStringList();
for(int i = 0; i < idListONE.size(); i++) {
std::cout << "FIRST STRING ITER" << std::endl;
firstTuple.push_back(&idListONE[i]);
}
FactsOrder.push_back(*facts->at(j).returnName());
std::cout << "creating first fact" << std::endl;
temporary = Relation(facts->at(j).returnName(), firstTuple);
} else {
std::cout << "processing A fact (ITER)" << std::endl;
// Populate this first vector with ID's from schemes.
std::vector<Token*> first;
first.clear();
std::cout << "processing fact, firststring (ITER)" << facts->at(j).returnFirstString()->getTokensValue() << std::endl;
first.push_back(facts->at(j).returnFirstString());
std::vector<Token> idLista;
idLista.clear();
std::cout << "getting stringlist (ITER)" << std::endl;
idLista = *facts->at(j).returnCleanStringList();
for(int i = 0; i < idLista.size(); i++) {
std::cout << "processing stringlist (ITER) ITER" << std::endl;
first.push_back(&idLista[i]);
}
FactsOrder.push_back(*facts->at(j).returnName());
std::cout << "adding fact" << std::endl;
temporary.relationInsert(facts->at(j).returnName(), first);
}
}
return temporary;
}
relation.cpp
Just so you can see it
Relation :: Relation(Token* key,std::vector<Token*> tuple)
{
std::pair<Token*,std::vector<Token*> > mypair (key,tuple);
contents.insert(mypair);
}
Relation :: Relation() {}
Relation :: ~Relation() {}
void Relation :: relationInsert(Token* key,std::vector<Token*> tuple)
{
std::pair<Token*,std::vector<Token*> > mypair (key,tuple);
contents.insert(mypair);
}
void Relation :: printRelation()
{
std::cout << "PRINT RELATION CALLED" << std::endl;
std::multimap<Token*,std::vector<Token*> >::iterator mapIT;
for(mapIT = contents.begin() ; mapIT != contents.end() ; mapIT ++) {
std::cout << "Key: " << mapIT->first->getTokensValue() "\nValues:" << std::endl;
for(int x = 0; x< mapIT->second.size() ; x++)
std::cout << " " << mapIT->second.at(x)->getTokensValue() << std::endl;
}
}
To solve your problem you must figure out object / pointer ownership in your code. Relation holds a relation between a pointer to Token and a list of other pointer to Tokens. It is ok to keep Token* rather then a copy of Token. (Especially if tokens can be large words you don't want to copy). But who "owns" and manages the tokens?
Lets look at an example
std::vector<Token*> firstTuple;
std::vector<Token> idListONE;
idListONE is a vector to actual Tokens. It is a function local variable so it will be discarded when we exit the function.
firstTuple is a vector to pointers of Tokens.
You push into it in the following manner:
firstTuple.push_back(&idListONE[i]);
So firstTuple tokens are pointers to the internal tokens inside idListONE. That might be valid but you must remember that as soon as idListONE is released or its memory is changed (its size increased for instance) firstTuple becomes invalid, because it will now point at memory that was released and using it may have undefined results and will likely crash the program.
Actually a few lines later you make that mistake:
temporary = Relation(facts->at(j).returnName(), firstTuple);
temporary is a Relation that holds a list to pointer of Tokens. It copies the list that means that it copies the token pointers. However the pointers it copies are to Tokens that belong to idListONE as soon as you exit the function idListONE is released and the pointers inside the Relation are no longer valid and using them is likely one source of the problems you are seeing. There might be additional problems like this in the code
In general there seems to be a lot of confusion about working with pointers vs working with objects.
Look at the following statement:
temp = *new Relation(input.returnFirstScheme()->returnName(), firstTuple);
new Relation(...) will allocate memory on the heap and initialize a Relation.
temp = *<ptr> will use operator= to copy the content on the right into temp. The Relation on the heap is forgotten and its memory is leaked.
Another example:
idListONE.clear();
std::cout << "FIRST STRINGLIST" << std::endl;
idListONE = *facts->at(j).returnCleanStringList();
first you clear idListONE then you use the operator= to overwrite it with a new list.
Why did you clear a list you are writing over?
Why do you return a pointer to a list from returnCleanStringList()? instead of a copy list or a const ref to an internal list? If you decided returnCleanStringList() should return a list by pointer rather then by value then why is the first thing you do is copying it?
Finally you really should choose one style and conform to it. In the long run it makes code clearer.
If you Camelize variable names then always do: idListONE -> idListOne
Also avoid members like 'idListONE', do you really need a different variables for the first index?
I have a class to store data that looks like this:
class DataLine
{
public:
std::string name;
boost::posix_time::time_duration time;
double x, y, z;
DataLine(std::string _name, boost::posix_time::time_duration _time, double _x,
double _y, double _z); //assign all these, not going to do it here
bool operator < (DataLine* dataLine) { return time < dataLine->time; }
}
Then I read in a bunch of data and .insert it into a std::set of the objects:
std::set<DataLine*> data;
data.insert( new DataLine(newname, newtime, newx, newy, newz) );
//...insert all data - IS OUT OF ORDER HERE
Then I run through my data and do stuff with it while appending new elements to the set.
boost::posix_time::time_duration machineTime(0,0,0);
for(std::set<DataLine*>::reverse_iterator it = data.rbegin(); it != data.rend(); ++it)
{
if(machineTime < (*it)->time)
{
machineTime = (*it)->time;
}
machineTime += processDataLine(*it); //do stuff with data, might add to append list below
for(std::vector<AppendList*>::iterator iter = appendList.begin(); iter != appendList.end(); ++iter)
{
data.insert( new DataLine( (*iter)->name, machineTime,
(*iter)->x, (*iter)->y, (*iter)->z); );
}
}
When I try to loop through the set of data both before and after inserting the elements all my data is out of order! Here are some times outputted when looped using
for(std::set<DataLine*>::iterator it = data.begin(); it != data.end(); ++it)
{
std::cout << std::endl << (*it)->time;
}
14:39:55.003001
14:39:55.003002
14:39:55.001000
14:39:59.122000
14:39:58.697000
14:39:57.576000
14:39:56.980000
Why aren't these times sorted in order?
It is sorted. It's sorted based on the data type you're storing in the set, which is a pointer to a DataLine. In other words, it'll sort according to the location in memory of your objects which is probably creation order (but may not be, depending on how the memory allocation functions work in your implementation).
If you want to sort based on the DataLine type itself, don't use a pointer. Store the objects themselves.
You can see a similar effect from the following code which creates two sets. The first is a set of integer pointers, the second a set of actual integers:
#include <iostream>
#include <iomanip>
#include <set>
using namespace std;
int main (void) {
set<int*> ipset;
set<int> iset;
cout << "inserting: ";
for (int i = 0; i < 10; i++) {
int val = (i * 7) % 13;
cout << ' ' << setw(2) << val;
ipset.insert (new int (val));
iset.insert (val);
}
cout << '\n';
cout << "integer pointer set:";
for (set<int*>::iterator it = ipset.begin(); it != ipset.end(); ++it)
cout << ' ' << setw(2) << **it;
cout << '\n';
cout << "integer set: ";
for (set<int>::iterator it = iset.begin(); it != iset.end(); ++it)
cout << ' ' << setw(2) << *it;
cout << '\n';
cout << "integer pointer set pointers:\n";
for (set<int*>::iterator it = ipset.begin(); it != ipset.end(); ++it)
cout << " " << *it << '\n';
cout << '\n';
return 0;
}
When you run that code, you see something like:
inserting: 0 7 1 8 2 9 3 10 4 11
integer pointer set: 0 7 1 8 2 9 3 10 4 11
integer set: 0 1 2 3 4 7 8 9 10 11
integer pointer set pointers:
0x907c020
0x907c060
0x907c0a0
0x907c0e0
0x907c120
0x907c160
0x907c1a0
0x907c1e0
0x907c220
0x907c260
You can see the unordered way in which values are added to the two sets (first line) and the way the pointer set in this case matches the order of input (second line). That's because the addresses are what's being used for ordering as you can see by the fact that the final section shows the ordered addresses.
Although, as mentioned, it may not necessarily match the input order, since the memory arena may be somewhat fragmented (as one example).
The set containing the actual integers (as opposed to pointers to integers) is clearly sorted by the integer value itself (third line).
You need to define member operator < like below, and save objects in std::set instead of raw pointers. Because for raw pointers, the default comparision criteria is based on the pointer value itself.
bool operator < (const DataLine &dataLine) const
{
return time < dataLine.time;
}
...
std::set<DataLine> data;