Overloading operator< for pointers to Objects?

Check out the simple code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <vector>
#include <algorithm>

class A
{
    private:
        int val;

    public:
        //ctr
        A(int v) : val(v){}

        // overloaded operator<
        bool operator<(A* p) const { return val < p->val; }

        // getter
        int getVal() { return val; }
};


int main()
{
    const int sz = 5;
	std::vector<A*> v;

	for (int i = 0; i < sz ; i++)
	{
		int val;
		std::cin >> val;

		A* p = new A(val);
		v.push_back( p );
	}

	std::sort(v.begin(), v.end() ); // sort vector by 'val'

	//print
	for (int i = 0; i < v.size(); i++)
	{
		std::cout << "Value: " << v[i]->getVal() << std::endl;
	}

	// delete memory associated with each pointer
	for(int i = 0; i < v.size(); i++) delete v[i];

	return 0;
}


Don't ask why im creating a vector of pointers rather than straight up objects, this is just for the sake of my question.

The code above does not actually sort my vector by val. It doesn't sort it at all. The overloaded operator< does not work for a vector of pointers to objects, apparently. But as soon as I change it to a vector of objects (and modify my operator< function little), the vector gets sorted perfectly.

So why is this the case? Why does the operator< overload get used for comparing two objects, but not for two pointers to objects? I suppose my confusion arises from the fact that my operator< function itself is not comparing pointers, but ints. So whats the problem with that? Not to mention that fact that the pointers to objects being compared (or rather, the ints associated with them), are all within one container. I would expect the outcome to be the same as in the case of vector of objects.


Last edited on
Why does the operator< overload get used for comparing two objects, but not for two pointers to objects
Because the operator signature compares an A with an A*.

An A* is not an A.

You could use a lambda instead of changing the semantics of < for your object, since probably a comparison between an A and an A* shouldn't compile

std::sort(v.begin(), v.end(), [] (A const *const a, A const *const b) { return a->val < b->val; } );
Last edited on
Your overloaded < operator isn't comparing two objects of type A. Nor is it comparing two pointers to objects of type A. It's a strange mix of the two.

I suggest you declare a friend function to compare two objects by pointer.
something like this:
 
    friend bool cmp(const A* left, const A* right);


define the function itself:
1
2
3
4
bool cmp(const A* left, const A* right)  
{ 
    return left->val < right->val;  
}


and use that function as a parameter in the sort:
 
    std::sort(v.begin(), v.end(), cmp );

Looks like the lambda as it stands has a problem, since it tries to access val which is private. Maybe change it to:
1
2
    std::sort(v.begin(), v.end(), 
        [] (A const *const a, A const *const b) { return *a < *b; } );

and then overload the operator < in the usual way for two A objects.
I know I can use a comparison function or even a functor. Im not asking about that.

Im asking why the operator< is not working with this?

Your overloaded < operator isn't comparing two objects of type A. Nor is it comparing two pointers to objects of type A. It's a strange mix of the two.
Because the operator signature compares an A with an A*.


Im not sure im understanding. Doesn't operator< take this pointer as an implicit argument? Thus both arguments are pointers to objects, and im simply comparing the int val associated with both.

If you guys can elaborate more on what exactly is wrong here, I think I can understand.
Last edited on
Doesn't operator< take this pointer as an implicit argument?

Reference, not a pointer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo {
  int x;
  int bar() {
    return x;
  }
};

// is like (pseudo)
class Foo {
  int x;
};

int bar( Foo & obj ) {
  return obj.x;
}
Doesn't operator< take this pointer as an implicit argument? Thus both arguments are pointers to objects, and im simply comparing the int val associated with both.


To compile the expression "a < b", the compiler looks at the type of a.

If the types of a and b are not class/struct/union/enum, it always the built-in operator< (note that means that there is no way to write an operator< that compares pointers!)

If the type of a is class/struct/union/enum, the compiler looks for every operator<(A, T) and A::operator<(T) it can find, and among those selects the ones where the type of b can be converted to T, and then among those, selects the one with the simplest conversion. (technically, the left parameter of the non-member overload can also be something to which A is convertible, but at least one parameter must be class/enum)

As mentioned, your A::operator<(A*) will be called for an expression "a < b", where a has type A and b has type pointer-to-A.

Check http://en.cppreference.com/w/cpp/language/operators for general ideas of how to overload operators and http://en.cppreference.com/w/cpp/language/overload_resolution#Call_to_an_overloaded_operator if you can handle semi-formal description.
Last edited on
Reference, not a pointer.

Are you sure?

"The type of this in a member function of class X is X* (pointer to X)."
http://en.cppreference.com/w/cpp/language/this

@Cubbi:
... and A::operator<(T) it can find ...


Right here. This is where im getting confused. There is an implicit this POINTER (i.e. A*) on the left hand side, and an explicit A* is being passed for the right hand side (as the vector is filled with elements of type A*). Im sorry if im being stubborn or repetitive, but im genuinely trying to understand this. Why aren't both parameters of type A*?

Isn't this: bool operator<(A* p) const { return val < p->val; }
the same as this: bool operator<(A* this, A* p) const { return this->val < p->val; } with the underlined portion being "invisible"?
Last edited on
to compile the expression a < b, in this case (with no non-member operator overloads), the compiler will attempt to call a.operator<(b). Not a->operator<(b): "a" is not permitted to be a pointer. (that is, if "a" is a pointer, it will be calling operator<(T*,T*), the built-in comparison of pointers to elements of the same array)
Last edited on
Taking a reference does not prevent from providing a pointer.
Topic archived. No new replies allowed.