Using lower_bound() with a set of objects in C++ - c++

I'm using a set of objects in C++ to get log(n) times for inserting and finding.
In the code below I'm able to insert elements and make them ordered by x attribute, however, I'm not able to use lower_bound to find the lower bounds based on the same attribute. I don't know how to fix that. Any help will be appreciated.
Most of the examples on sets that I could find were not about a set of objects
struct MyObject {
float x = 0;
float y = 0;
const bool operator < ( const MyObject &r ) const{
return ( x< r.x);
}
};
set<MyObject> nset;
int main(){
MyObject n1;
n1.x=5;
n1.y=1;
MyObject n2;
n2.x=3;
n2.y=2;
nset.insert(n1);
nset.insert(n2);
// this works, the elementes are sorted according to x
for(auto elem: nset){
cout << elem.x << endl;
}
// this doesn't work
set<MyObject>::iterator it = lower_bound(nset.begin(), nset.end(), 1.2);
cout << it->x << endl;
//neither this one
// set<MyObject>::iterator it = nset.lower_bound(1.2);
// cout << it->x << endl;
cout << "hello" << endl;
return 0;
}
I want the lower bound function to point me to the lower bound "x" in the set of objects but the code fails to compile. Compiler error to the first lower bound says: Invalid operands to binary expression ('const MyObject' and 'double')
Compiler error to the second lower bound says: No matching member function for call to 'lower_bound'
EDIT: while the answer provided by user: 1201ProgramAlarm was quite helpful for me to understand and fix the error. I still think it is more convenient in my case to have a lower_bound function that accepts floats rather than objects. So I have implemented the following function to help me achieve that. Copied below just in case others were interested:
set<MyObject>::iterator mylower_bound(set<MyObject> &myset, float val){
MyObject f;
f.x = val;
set<MyObject>::iterator it = myset.lower_bound(f);
return it;
}

nset stores MyObject objects, and lower_bound needs one of the thing stored in the set. You're passing it 1.2, which is a double, but there is no way to construct a MyObject from a double. Thus the compilation failure.
You'll need to pass a MyObject to nset.lower_bound to do your search.

Related

How can I iterate over a vector of functions and call each of them in C++?

I am trying to loop through an array of functions stored in a vector, and i want to call each of them by the iterator pointer object,
but something like this:
itr->funcs[i](5); // call the ith index function && pass int 5 as param
is not the solution i guess, what is the solution then ?
Below is my code, please check the last for loop in the code.
#include <iostream>
#include <string>
#include <vector>
// to be able to take other functions as arguments in a function
#include <functional>
using namespace std;
// receive other functions inside a function
// syntax: return_type function_name(std::function<return_type(parameter_lists)>func_name, parameter_lists)
double doMath(std::function<double(double)> someOtherFunction, double num){
return someOtherFunction(num);
}
double multBy2(double d){
// b'coz x is pointing to multBy2 the word 'someOtherFunction' in the
// above function behaves like an alias for this function 'multBy2'
return d * 2;
}
double multBy3(double d){
return d * 3;
}
int main (){
// dec && init
auto x = multBy2; // x pointing to multBy2 now
std::cout << "2 * 5.1 : " << x(5.1) << "\n";
std::cout << "multBy2 will be called: " << doMath(x, 6.1) << "\n";
std::cout << "multBy2 will be called, again: " << doMath(x, 6.1) << "\n";
// store different functions inside a vector
// you must use the same signature type functions
std::vector<function<double(double)>> funcs(2);
funcs[0] = multBy2; // multBy2 stored at the zeroth index
funcs[1] = multBy3; // multBy3 stored at the first index
// check
// funcs[0](10), pass value by index
std::cout << "2 * 10 = " << funcs[0](10) << "\n";
std::cout << "3 * 10 = " << funcs[1](10) << "\n";
// loop through them
for (auto itr = funcs.begin(); itr != funcs.end(); itr++){
// iterate through the functions
// itr->funcs[1](10); // I KNOW THIS IS WRONG, WHAT SHOULD I WRITE HERE?
}
return 0;
}
The variable itr is an iterator, which is basically a pointer, i.e. they both point to to an object. In this case the iterator is pointing to a function. You can get to the function by dereferencing itr (much like a pointer) with *itr. Then you can use this object like it's a function (because it is one):
for (auto itr = funcs.begin(); itr != funcs.end(); ++itr)
(*itr)(10); // like calling func[i](10)
Since it's an iterator, you might also want to use the -> operator, so that you can use the pointed at object directly. Unfortunately, if you tried to do what might seem like the obvious thing:
itr->(10); // error
the syntax of the language just doesn't allow it (parentheses can be tricky to figure out, even for a compiler). Fortunately, the language does have a way of allowing you to explicitly say what you mean, which is, "I just want to treat it like a function, so I can call it with ()". There is a function called the call operator which is spelled operator() that you can use. The syntax for that is:
for (auto itr = funcs.begin(); itr != funcs.end(); ++itr)
itr->operator()(10);
However, this syntax does seem to defeat the purpose of using the convenient -> operator in the first place.
However, I recommend that you use a range-for loop here (it's usually the better choice if you can use it). The syntax is much clearer at expressing the intent of the code:
for (auto &func : funcs) // for every function in funcs
func(10); // use the function
Here's a working demo.

Passing class with array member into overload of function that uses that array member

I'm trying to implement a polynomial class consisting of an int (degree) and an integer array (the coefficients for each term). I have a function to print the polynomial, which works fine when I pass in the degree and term array directly, but things get funky when I try to put those values into an instance of my polynomial class.
I am using variadic arguments in the polynomial's constructor, such that you should be able to call polynomial(degree, ). I made sure to output each term in my va_list so I know I'm targeting what I want to.
Here's my class:
class polynomial{
public:
polynomial(int degree...){
va_list args;
_degree = degree;
int p[degree];
va_start(args,degree);
for(int i = 0; i < degree; i++){
p[i] = va_arg(args,int);
cout << p[i] << endl; //just to verify that I'm grabbing the right values.
}
va_end(args);
_terms = p;
}
int degree(){return _degree;}
int* terms(){return _terms;}
private:
int _degree;
int* _terms;
};
And here's the function(s) I'm using to print the polynomial:
void printArray(int*p, int l){
std::cout << "[";
for(int i = 0; i < l; i++){
std::cout << p[i];
if(i != l-1) std::cout << ",";
}
std::cout << "]" << std::endl;
}
void printArray(polynomial p){
printArray(p.terms(), p.degree());
}
my main function:
int main()
{
int a[3] = {2,5,3};
printArray(a,3);
polynomial p1(3,2,5,3);
printArray(p1.terms(), p1.degree());
printArray(p1);
return 0;
}
and the output:
[2,5,3]
2
5
3
[2,0,94004573]
[1,0,1]
As you can see, I call printArray() 3 times. The first time, I directly create an integer array and pass it and its length into printArray(). This time, it works fine, outputting [2,5,3] as expected. The second time, I again use the first implementation of printArray(), but this time I pass in the int* and int from an instance of my polynomial. This time, I get some array whose first two elements always seem to be 0 and 2 and whose last value is some garbage value.
The third time, I simply pass in the polynomial to the second implementation of printArray(). This seems to output [1,0,1] consistently (which is of course incorrect).
I suppose it wouldn't be too confusing if the second and third calls to printArray() generated the same garbage values, but as it stands, I am fairly lost in terms of what's happening behind the scene. Any help at all would be appreciated. Thank you!
The problem is these two lines:
int p[degree];
and
_terms = p;
The first (besides not being a non-portable variable-length array extension of your compiler) defined p to be a local variable.
The second line makes _terms point to the first element of this array.
Then the constructor ends, and the life-time of p with it, leaving you with an invalid pointer in _terms.
The natural solution is to use std::vector instead. And if you need to use pointers (because assignment/exercise requirements) you need to use dynamic allocation (using new[], and also then you need to learn about the rule of three/five).

Retrieval of value back from C++ map<T, const T&> returns same object

I created a map of type map<T, const T&>. For current example purpose, let say T is:
class Bar {
public:
Bar(int x) {this->x = x;}
int x;
};
Next I create a map and insert Bar keyed with some integers.
Bar bs[] = {Bar(1), Bar(2), Bar(3)};
map<int, const Bar&> my_map;
for (int i = 0; i < 3; i++) {
const Bar &b = bs[i];
cout << "Setting map." << i
<< " with x = " << b.x << endl ;
my_map.insert(std::make_pair(i, b));
}
So far everything looks good, and b.x prints the values 1; 2; 3 as expected. Next we retrieve these values back.
for (int i = 0; i < 3; i++) {
auto iter = my_map.find(i);
if (iter == my_map.end()) {
cout << "Not found!" << endl;
continue;
}
cout << "map." << i << " = " << iter->second.x << endl;
}
The output prints the last value each time as shown below.
// map.0 = 3
// map.1 = 3
// map.2 = 3
And that's what is confusing to me, as I expect 1; 2; 3. If I replace value type of map with just const Bar it gives 1; 2; 3. I've been trying to make sense out of it, but so far it just looks like undefined behaviour to me. The wildest explanation I can imagine is that &b is like a box storing pointer to the object, and the box ends up being shared across loop, and make_pair uses &b as a box value than like a pointer/reference (and hence explains the last value being printed).
Edit: I understand it may not be good idea to use map like this, but I'm curious why this is happening than what should I be using instead. As in semantically, what did I miss when I wrote this and why it went through compiler, or why compiler made whatever assumption it made.
Edit: Example on repl.it running the code: https://repl.it/repls/IgnorantExhaustedBluejay
Essentially the same problem as here: How can I have a pair with reference inside vector?
Your call to std::make_pair creates a temporary std::pair object that does not have a reference as its second member. The second member of the pair is a regular value of type Bar. Meanwhile, your map stores references. The reference gets bound to the second member of the temporary created by std::make_pair. Later the temporary gets destroyed. The reference becomes dangling.
Each temporary on each iteration of the cycle is apparently created at the same location in memory. So, all these dangling references in your map refer to the same location in memory. Which just happens to hold the residual value of 3 at the time of printing. That explains the output.
A map with raw references is not a very good idea. But if you want to somehow force it to work with raw references, stop using std::make_pair. Instead, manually construct a proper std::pair, making sure to explicitly specify the proper types
my_map.insert(std::pair<const int, const Bar &b>(i, b));
Or you can keep using std::make_pair as follows
my_map.insert(std::make_pair(i, std::cref(b)));
But switching entirely to std::reference_wrapper and std::cref is a better idea.
P.S. BTW, in C++17 mode GCC refuses to compile the code with raw references. C++14 mode does compile it.
I wasn't even aware that it's possible to have a map of references
You should probably simply store the object you want directly :
map<int, Bar> my_map;
If you want the "Bar"s objects to live outside the map, you should use pointers instead of references. Just be sure you don't destruct the Bar objects without removing them from the map :
map<int, Bar*> my_map;
my_map[2] = &bs[0];
and then:
int x = my_map[2]->x;
Edit
I think the map is holding a reference to the temporary pair. You can see this in debug if you extract the creation of the pair :
auto tempPair = std::make_pair(i, b);
my_map.insert(tempPair);
Then after adding bs[0] if we run the creation of the pair, the value of my_map[0] change even before adding the second one:
This makes it work:
my_map.insert(std::make_pair(i, std::reference_wrapper<const Bar>(b)));

C++ / How does a iterator work for a Set of class object?

I've been teaching myself C++, and found an interesting thing.
According to this web page,:
The most obvious form of iterator is a pointer.
So, I used to think that an iterator object works in almost the same way as a pointer (e.g. int *i);
However, now I guess that it would be more accurate to say an iterator object is like a pointer of a pointer (such as int **i) rather than a pointer (int *i).
I noticed this, when I was coding the following one.
set<Point*, Point> points; //This class encapsulates x and y coordinates for a 2 dimensional point
set<Point*, Point>::iterator it;
int x = 22;
int y = 4;
Point* pt = new Point(x, y);
points.insert(pt);
//Similar statements are here, to insert other Point objects with different arguments
for (it = points.begin(); it != points.end(); it++) {
cout << "**it: " << **it << ", *it :" << *it << ", Address : " << &it << endl;
}
As a result,
**it showed values of Pointer class objects
*it showed addresses
&it showed the address of the it object
So, is it right to say that an iterator object (it) is basically the same as **it?
Another question which is a bit different from iterators:
If I need to make a set of class object, like: set<ClassName*, ClassName> SetName;, what would be the correct way? (as long as this class contains comparable data type, like int or double)
I'd appreciate if you'd give some advice.
It is a wrong assumption. In your example the value_type of the set is pointer Point *. And *it gives you an element in the set that is a reference to some object of this value_type that is of type Point * and ++it "points" to the next element in the set. So the iterator behaves the same way as pointer to an object of value_type.
When you use expression like **it then the second dereference is not applied to the iterator. It is applied to an object in the set. You can imagine expression **it the following way
Point *pp = *it;
Point p = *pp;
Iterator of a container is responsible to provide you access to elements of the container. Thus if elements in the container has type value_type then the iterator provides access to these elements of this value_type. The elements in turn can be pointers to objects or even pointers to pointers to objects and so on.
As for your second question then if the class has the corresponding operator function and the class itself has some simple default constructor then you may use such an approach though it would be better to define a separatw comparator or simply to define operator < for objects of the class. In the last case you can write
std::set<Point> s;
without explicit second template argument.
Here is demonstrative program of your approach
#include <iostream>
#include <set>
int main()
{
struct Point
{
int x, y;
bool operator ()( const Point &p1, const Point &p2 ) const
{
return p1.x < p2.x && p1.y < p2.y;
}
};
std::set<Point, Point> s;
s.insert( { 2, 2 } );
s.insert( { 1, 1 } );
for ( const Point &p : s ) std::cout << p.x << ' ' << p.y << std::endl;
return 0;
}
The program output is
1 1
2 2

C++ assign dereference pointer object to a variable and use that

Hea everyone!
First of all, I am a completely new to C++ coming from a basic C background so it might be a little weird why I ask this.
The use scenario is that I want to change a map inside a different function by passing the map as a pointer to that function. Because I was reusing someone else's code, it was easier to assign the dereference to a variable instead of changing all of the references. This results in a similar case as this:
using namespace std;
typedef map<long, double> tl_t;
void fillmap(tl_t* m_p) {
tl_t m = *m_p;
m.insert(pair<long, double>(4, 3.0));
}
int main(int argc, char** argv) {
tl_t m;
cout << "Size: " << m.size() << "\n";
fillmap(&m);
cout << "Size: " << m.size() << "\n";
return 0;
}
The funny thing is that now both Size: strings return 0 and the original map m in the main function does not seem to be changed. This, however, works:
using namespace std;
typedef map<long, double> tl_t;
void fillmap(tl_t* m) {
(*m).insert(pair<long, double>(4, 3.0));
}
int main(int argc, char** argv) {
tl_t m;
cout << "Size: " << m.size() << "\n";
fillmap(&m);
cout << "Size: " << m.size() << "\n";
return 0;
}
As far as I can tell, these 2 cases should be working the same as both the reference of m in the main and fillmap function reference the same object. Of course the two m variables reside somewhere differently but should be referencing the same object.
As I am writing this, one thing that might be the problem is that variable m in main IS the map object while the variable m in fillmap TRIES to be the map object but can't because dereferencing the m_p pointer and assigning it to that last m doesn't actually make the last m a reference to the same object but actually copies it. Am I on the right track here?
And yes, I do know in normal use cases you should use a parameter reference in a similar situation, but this bugged the hell out of me :P.
Hopefully someone can enlighten me!
In C++ you have to add & to explicitly say that variable is reference.
In your example:
tl_t& m = *m_p;
should help.
If you use just "tl_t" you create local copy of the object which is destroyed once you leave fillmap function.
Example:
struct X {
int a,b;
}
Now types:
X - place in memory containing both a and b value.
X& - place in memory containing reference (const pointer) to the X.
X* - place in memory containing pointer to the X.
In both X and X& you can access fields of class using dot (xobject.a, xobject.b) but these are not same types.
It is because that
tl_t m = *m_p;
m will be construct by call the copy constructor, the copy process is by value. You just insert the pair<long, double>(4, 3.0) into m, not m_p
However,
(*m).insert(pair<long, double>(4, 3.0))
*m is the object you passed in by pointer, so, the pair<long, double>(4, 3.0) is inserted to *m itself.