This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[c++0x] shared_ptr get() and use_count() inconsistency


Hi, I've been playing with shared_ptr and its aliasing constructor and the following code doesn't work as expected:

int main()
{
    std::shared_ptr<int> aux;
    int i;
    std::shared_ptr<int> aux2(aux, &i);
    assert(aux2.use_count() == 0);
    assert((bool)aux2, false); // assert failure here
    assert(aux2.get() == NULL); // assert failure here
}

I know there's no C++0x standard yet, blah blah blah, but in current libstdc++ implementation shared_ptr's get returns something different than NULL even when use_count()==0.

The current standard draft says that use_count() should return 0 if the shared_ptr is empty, and get() should return NULL if the shared_ptr is also empty.

The current implementation simply returns the stored pointer, whether use_count() is 0 or not.

I've attached a patch with two possible solutions. The first (shared_ptr.diff) just checks if use_count()==0 before returning the stored pointer, if it is, returns NULL. Is also changes operator-> and operator* to use get() with the correct semantics. This problem is that this solution incurs some overhead, with an addition of an comparison.

The second solution (shared_ptr_fast.diff) sets the stored pointer to NULL in the aliasing ctor if the shared_ptr to be aliased has use_count()==0. AFAIK, the semantics is the same of the last solution, but this one is faster because the comparison is done just one time. I didn't check if this has bad side effects I didn't think of.

Regards,
Rodolfo Lima.
--- boost_shared_ptr.h	2008-03-17 23:36:08.000000000 -0300
+++ boost_shared_ptr_new.h	2008-06-05 01:31:14.000000000 -0300
@@ -460,20 +460,20 @@
 #endif
       operator*() const // never throws
       {
-	_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
-	return *_M_ptr;
+	_GLIBCXX_DEBUG_ASSERT(use_count() != 0);
+	return *get();
       }
 
       _Tp*
       operator->() const // never throws
       {
-	_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
-	return _M_ptr;
+	_GLIBCXX_DEBUG_ASSERT(use_count() != 0);
+	return get();
       }
     
       _Tp*
       get() const // never throws
-      { return _M_ptr; }
+      { return use_count()!=0?_M_ptr:0; }
 
       // Implicit conversion to "bool"
     private:
@@ -481,7 +481,7 @@
 
     public:
       operator __unspecified_bool_type() const // never throws
-      { return _M_ptr == 0 ? 0 : &__shared_ptr::_M_ptr; }
+      { return get() == 0 ? 0 : &__shared_ptr::_M_ptr; }
 
       bool
       unique() const // never throws
--- boost_shared_ptr.h	2008-03-17 23:36:08.000000000 -0300
+++ boost_shared_ptr_new.h	2008-06-05 01:36:10.000000000 -0300
@@ -291,8 +291,13 @@
        */
       template<typename _Tp1>
         __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, _Tp* __p)
-	: _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws
-        { }
+	: _M_refcount(__r._M_refcount) // never throws
+        { 
+		if(__r.use_count() != 0) 
+			_M_ptr = __p; 
+		else
+			_M_ptr = 0;	
+	}
 #endif
 
       //  generated copy constructor, assignment, destructor are fine.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]