• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 604
  • Last Modified:

STL Set Element Ordering Relationship for Boost Shared_Ptr

Hi,

I wanted to see how boost shared_ptr works hence I copied one example code snippet from boost documentation and was testing it. I have attached it here. I tested it on windows with visual studio 2010 IDE. If you compile and check the output, you will see that if we insert elements just in to "set", it is getting inserted and automatically sorted. But the moment we try to insert same elements in vector, approximately after 3rd element, the order of insertion changes. Also, duplicate values are getting inserted without any problem. Destruction odrer looks fine.

My questions are -

1. Is this behavior because we are storing shared_ptr objects? Is it sorting based on pointers?  
2. Is vector push_back really affecting insertion mechanism of "set"?
3. How exactly "reset" works? Does it create multiple copies or just adds to reference counting?
4. How can I ensure that elements (shared_ptr type) are inserted in the order of insertion or sorted based on value?
5. How can "set" avoid inserting duplicate element which is expected since its the natural behaviour and works when we insert primitive types?

Any relevants links will be appreciated.

The output of attached program looks like below  -

Inserted 1
1

Inserted 5
1
5

Inserted 6
1
5
6

Inserted 3
1
5
3
6

Inserted 4
1
5
3
6
4

Inserted 2
1
5
3
6
4
2

Inserted 3 again
1
5
3
6
4
2
3

Size of Foo set is ----> 7

Destructing Foo 3
Destructing Foo 2
Destructing Foo 4
Destructing Foo 6
Destructing Foo 3
Destructing Foo 5
Destructing Foo 1

Thanks.

 
#include <vector>
#include <set>
#include <iostream>
#include <algorithm>
#include <boost/shared_ptr.hpp>

using namespace std;

struct Foo {
	Foo(int x_) : x(x_) {
	}
	~Foo() {
		cout << "Destructing Foo " << x << endl;
	}


	int x;
};

typedef boost::shared_ptr<Foo> Foo_Ptr;

struct FooPtrOps {

	void operator () (const Foo_Ptr & a) {
		cout << a->x << endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	set<Foo_Ptr> foo_set;
	vector<Foo_Ptr> foo_vec;

	Foo_Ptr fooptr (new Foo(1) );
	foo_vec.push_back(fooptr);
	foo_set.insert(fooptr);

	cout << "Inserted 1\n";
	for_each(foo_set.begin(), foo_set.end (), FooPtrOps());
	cout << "\n";

	fooptr.reset( new Foo(5) );
	foo_vec.push_back(fooptr);
	foo_set.insert(fooptr);

	cout << "Inserted 5\n";
	for_each(foo_set.begin(), foo_set.end (), FooPtrOps());
	cout << "\n";

	fooptr.reset( new Foo(6) );
	foo_vec.push_back(fooptr);
	foo_set.insert(fooptr);

	cout << "Inserted 6\n";
	for_each(foo_set.begin(), foo_set.end (), FooPtrOps());
	cout << "\n";

	fooptr.reset( new Foo(3) );
	foo_set.insert(fooptr);

	cout << "Inserted 3\n";
	for_each(foo_set.begin(), foo_set.end (), FooPtrOps());
	cout << "\n";

	fooptr.reset( new Foo(4) );
	foo_set.insert(fooptr);

	cout << "Inserted 4\n";
	for_each(foo_set.begin(), foo_set.end (), FooPtrOps());
	cout << "\n";

	fooptr.reset( new Foo(2) );
	foo_set.insert(fooptr);

	cout << "Inserted 2\n";
	for_each(foo_set.begin(), foo_set.end (), FooPtrOps());
	cout << "\n";

	//Adding duplicate of 3
	fooptr.reset( new Foo(3) );
	foo_set.insert(fooptr);

	cout << "Inserted 3 again \n";
	for_each(foo_set.begin(), foo_set.end (), FooPtrOps());
	cout << "\n";

	cout << "Size of Foo set is ----> " << foo_set.size() << "\n" << endl ;

	return 0;
}

Open in new window

0
James Bond
Asked:
James Bond
1 Solution
 
Infinity08Commented:
>> 1. Is this behavior because we are storing shared_ptr objects? Is it sorting based on pointers?  

Indeed. If you want to sort on a different criterium, you'll need to provide a comparator when constructing the set (see http://www.cplusplus.com/reference/stl/set/set/ for an example).


>> 2. Is vector push_back really affecting insertion mechanism of "set"?

No.

>> 3. How exactly "reset" works? Does it create multiple copies or just adds to reference counting?

The reset member function of boost::shared_ptr replaces the current pointer with a new one. This decrements the reference count by one for the old pointer, and increments it by one for the new pointer.

>> 4. How can I ensure that elements (shared_ptr type) are inserted in the order of insertion or sorted based on value?

See my answer for 1. above.

>> 5. How can "set" avoid inserting duplicate element which is expected since its the natural behaviour and works when we insert primitive types?

See my answer for 1. above.
0
 
James BondSoftware ProfessionalAuthor Commented:
Thanks infinity08. It works that way.

For others benefit this is what I did. I added below method in struct FooPtrOps -

 bool operator()( const Foo_Ptr & a, const Foo_Ptr & b )
    { return a->x < b->x; }

And while constructing set container, I added FooPtrOps as 2nd parameter -

set<Foo_Ptr, FooPtrOps > foo_set;

Thats it.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now