list::unique

Could someone explain to me how the unique function works here ?

1
2
3
4
5
6
7
8
9
10
11
class pred{
    public:
    bool operator()(int a,int b){
	     return a<b;
    }
};

//.....
list<int>a{2,4,6,5,3};

a.unique(pred());


When I print the elements, it only displays 2. To my understanding it should print 2,6,5,3, since the function should remove consecutive < elements.
Last edited on
Read the description for (2) carefully:
http://www.cplusplus.com/reference/list/list/unique/?kw=list%3A%3Aunique

The second version (2), takes as argument a specific comparison function that determine the "uniqueness" of an element. In fact, any behavior can be implemented (and not only an equality comparison), but notice that the function will call binary_pred(*i,*(i-1)) for all pairs of elements (where i is an iterator to an element, starting from the second) and remove i from the list if the predicate returns true.

Note that the predicate is called with the second number as the first argument and the preceding number as the second argument.

unique will iterate through the list starting with a comparison for 4 and 2. Your predicate will return false so 4 is not deleted. Ditto for 6 and 4. Now with 5 and 6 your predicate will return true, so 5 will be deleted. Finally for 3 and 6, your predicate will return true, thereby removing 3. You should end up with {2,4,6}.

Last edited on
Thanks for the reply. I understand your explanation, however there is a problem somewhere since VS2013 ends up just with element {2}.

I'm compiling this code:

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
#include <iostream>
#include <list>
using namespace std;



class pred{
public:
	bool operator()(int a,int b){
		return a<b;
	}
};


int main(){
	list<int>a{2,4,6,5,3};
	a.unique(pred());

	for(const int& i :a){
		cout<<i<<" ";       // prints '2'
	}

	cin.sync();
	cin.ignore();
	return 0;
}

Last edited on
I get the same results as you.
Comparing: 2 < 4
Should delete: 2
Comparing: 2 < 6
Should delete: 2
Comparing: 2 < 5
Should delete: 2
Comparing: 2 < 3
Should delete: 2
2

It certainly appears the arguments are being passed in the wrong order.
will call binary_pred(*i,*(i-1))

That certainly says that binary_pred should have been called with 4,2. That's not what my cout shows.
Try adding this to see what is going on:

1
2
3
4
    bool operator()(int a,int b){
        cout << "a=" << a << ", b=" << b << ", a<b=" << (a<b) << endl;
        return a<b;
    }
But even if the arguments were passed in the wrong order, the output shouldn't be just 2, right ?

PanGalactic, I'm on my phone right now, will compile that tomorrow.
Checking the reference page here:
http://en.cppreference.com/w/cpp/container/list/unique
I get a little different take on the issue.

Removes all consecutive duplicate elements from the container. Only the first element in each group of equal elements is left.

The cppreference.com page makes no assertion about the order of the arguments to the predicate. Since it seems to be expecting a test for equality, the order of arguments to the predicate would not be expected to make a difference. The underlined portion of the quote would imply that if true is returned, the second number is deleted, which matches with what we're seeing.

edit:
But even if the arguments were passed in the wrong order, the output shouldn't be just 2, right ?

Yes, it makes perfect sense. In the cout displays I provided above, I was assuming that the first argument was being deleted (per the documentation on this site). If you change the "should delete" to the second argument, then all you are left with is {2}.

Run assumes second argument to predicate is deleted:

Comparing: 2 < 4 (true)
Should delete: 4
Comparing: 2 < 6 (true)
Should delete: 6
Comparing: 2 < 5 (true)
Should delete: 5
Comparing: 2 < 3 (true)
Should delete: 3
2
Last edited on
Everything is clear now. Thank you very much :)
I was going to report this as an error on the list::unique page, but in checking the C++14 standard ยง 23.3.4.6 I see the same wording that is on this site's list::unique page.
Effects: Erases all but the first element from every consecutive group of equal elements referred to by the iterator i in the range [first + 1,last) for which *i == *(i-1) (for the version with no arguments) or pred(*i, *(i - 1)) (for the version with a predicate argument) holds. Invalidates only the iterators and references to the erased elements.

The C++17 standard also has the same wording. So bottom line, chalk this up to a peculiarity of the MS implementation.

Last edited on
Topic archived. No new replies allowed.