实例代码:
// test1.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <string.h> #include <string> #include <memory> #include <list> #include <iostream> using namespace std; using namespace std::tr1; class CInt: public enable_shared_from_this<CInt> { public: CInt( int _value):value_(_value){} ~CInt(){} int GetValue() { return value_;} bool operator==( const CInt & other ) const { return value_ == other.value_; } bool operator < ( const CInt & other ) const { return value_ < other.value_; } protected: private: int value_; }; bool SPIntCmp( shared_ptr<CInt> & c1, shared_ptr<CInt> & c2) { return c1 < c2; } bool SPIntValueCmp( shared_ptr<CInt> & c1, shared_ptr<CInt> & c2) { return *c1 < *c2; } int _tmain(int argc, _TCHAR* argv[]) { list< shared_ptr<CInt> > ilist; ilist.push_back( shared_ptr<CInt>( new CInt(1))); ilist.push_back( shared_ptr<CInt>( new CInt(3))); ilist.push_back( shared_ptr<CInt>( new CInt(5))); ilist.push_back( shared_ptr<CInt>( new CInt(7))); ilist.push_back( shared_ptr<CInt>( new CInt(9))); ilist.push_back( shared_ptr<CInt>( new CInt(2))); ilist.push_back( shared_ptr<CInt>( new CInt(4))); ilist.push_back( shared_ptr<CInt>( new CInt(6))); ilist.push_back( shared_ptr<CInt>( new CInt(8))); ilist.push_back( shared_ptr<CInt>( new CInt(10))); cout<<"Before sort"<<endl; for ( auto it = ilist.begin(); it != ilist.end(); it++) { shared_ptr<CInt> i = *it; cout<< i->GetValue()<<" "; } cout<<endl; ilist.sort(); cout<<"after default sort"<<endl; for ( auto it = ilist.begin(); it != ilist.end(); it++) { shared_ptr<CInt> i = *it; cout<< i->GetValue()<<" "; } cout<<endl; ilist.sort(SPIntCmp); cout<<"after SPIntCmp sort"<<endl; for ( auto it = ilist.begin(); it != ilist.end(); it++) { shared_ptr<CInt> i = *it; cout<< i->GetValue()<<" "; } cout<<endl; ilist.sort(SPIntValueCmp); cout<<"after SPIntValueCmp sort"<<endl; for ( auto it = ilist.begin(); it != ilist.end(); it++) { shared_ptr<CInt> i = *it; cout<< i->GetValue()<<" "; } cout<<endl; return 0; }输出:
Before sort
1 3 5 7 9 2 4 6 8 10
after default sort
9 2 4 6 8 10 1 3 5 7
after SPIntCmp sort
9 2 4 6 8 10 1 3 5 7
after SPIntValueCmp sort
1 2 3 4 5 6 7 8 9 10
请按任意键继续. . .
从结果可以看到调用 list.sort() 和list.sort(SPIntCmp)方法输出结果是一样的。都是错误的结果。
只有调用list.sort(SPIntValueCmp)的输出结果还是真确的。
这是因此 list的sort()是调用容器对象的 operator<方法,容器对象是什么?这里容器对象是 shared_ptr<CInt> 而不是CInt,因此并不会调用 CInt的operator <方法进行比较,而是调用shared_ptr<CInt>的operator<方法进行比较。查看shared_ptr源代码后,发现 shared_ptr的默认实现方式是根据资源的指针地址进行比较的,因此我们无法得到正确的排序结果。
对于此事,我们必须定制自己的Compare方法。在SPIntCmp方法中,我们调用的还是 shared_ptr的operator <方法,因此效果和list.sort()的结果是一样的。
在SPIntValueCmp中,我们使用的是shared_ptr管理的资源的值进行比较(这边代码省略了null ptr的判断处理,实际代码需要加上),此事调用的才是 CInt对象的operator<方法,因此能得到正确的结果。
如果 list<CInt *> 的sort()结果应该和list<shared_ptr<CInt> >的结果都是一样不可预料的。
根本原因是shared_ptr是按照引用来比较的而不是引用的值进行比较的,因此在使用shared_ptr时,对于在逻辑语意上相等的对象,一定要从同一个数据中构造shared_ptr对象,而不要从一个新的一模一样的副本中构造shared_ptr
例如
shared_ptr<CInt> c1( new CInt(1) );
shared_ptr<CInt> c1_1( new CInt(1));
对 c1 == c1_1 的结果是 false,而不是true,而 c1 < c1_1 结果并不一定是false,而是由CInt对象的地址决定,因此他们的引用不是同一个对象,虽然他们的引用是相等的2个对象。应该像下面这样使用
shared_ptr<CInt> c1( new CInt(1) );
shared_ptr<CInt> c1_1( c1
);
是否感觉到shared_ptr很像Java的Object对象。Java对象默认也是根据引用来比较的,如果要根据对象的语意进行相等比较必须重载 equal方法。可惜shared_ptr没有提供这样的方式让我们可以直接比较shared_ptr受控对象的语意相等性。只能选择根据地址来比较。