C#
  Home arrow C# arrow Page 2 - SatView: Pointer Perfect, part 3.5
ASP Free Forums 
.NET  
ASP  
ASP Code  
ASP.NET  
ASP.NET Code  
BrainDump  
C#  
Code Examples  
Database  
Database Code  
IIS  
Microsoft Access  
MS SQL Server  
Visual Basic.NET  
Windows Scripting  
Windows Security  
XML  
ASP Web Hosting  
ASP.NET Web Hosting 
Mobile Linux 
App Generation ROI 
Windows Web Hosting
 
IBM® developerWorks 
Sun Developer Network 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
C#

SatView: Pointer Perfect, part 3.5
By: J. Nakamura
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 1
    2004-12-20

    Table of Contents:
  • SatView: Pointer Perfect, part 3.5
  • BOOST::SHARED_PTR.
  • SMART PIMPL
  • BOOST::WEAK_PTR

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    SatView: Pointer Perfect, part 3.5 - BOOST::SHARED_PTR.


    (Page 2 of 4 )

    Your concept of ownership might lure you into the intuitive view of regarding a smart pointer to be reference counted. There are different ways to interpret the behavior “the smart pointer deletes the object it holds when it is no longer needed.”

    In fact, you have seen that ownership is transferred when auto_ptrs are copied, rendering the original auto_ptr invalid (i.e. you should not dereference it anymore), while you would expect a smart pointer to remain valid after a copy of it was made. Objects are normally not modified when they are being copied! You might like the object held by the smart pointer to be deleted when both the original smart pointer and its copy are not needed anymore. In that case you need a reference counted smart pointer like the boost::shared_ptr.

    The boost::shared_ptr tracks how many pointers are referring to an object and frees it only after the last pointer is not needed anymore. Let's adopt the code example again:

    void foo() {
    boost::shared_ptr<MyClass> pMyObj(new MyClass);
    /* perform some operations here */
    boost::shared_ptr<MyClass> pMyObj2 = pMyObj;
    (void)printf(“MyClass: %d references.\n”, pMyObj->use_count());
    }

    The use_count() function is useful when debugging a boost::shared_ptr, because it returns the reference count of the smart pointer (2 in this example). MyClass is still destructed when we leave the scope of this function, so this example doesn’t really highlight the differences between the scoped_ptr and the auto_ptr. Lets look at another code example.

    First we need some includes:
    #include <stdio.h>
    #include <memory>
    #include <boost/scoped_ptr.hpp>
    #include <boost/shared_ptr.hpp>

    Then we redefine MyClass:

    class MyClass {
    public:
      MyClass()  { (void)printf(“>> MyClass constructed <<\n”); }
      ~MyClass()  { (void)printf(“>> MyClass destructed <<\n”); }
    };


    And define three functions, that accept a smart pointer as a function parameter:

    void foo(std::auto_ptr<MyClass>) {
      (void)printf(\t\tenter foo(auto_ptr).\n”);
      (void)printf(\t\tdo some operations here.\n”);
      (void)printf(\t\tleave foo(auto_ptr).\n”);
    }
    void foo(boost::scoped_ptr<MyClass>) {
    (void)printf(\t\tenter foo(scoped_ptr).\n”);
    (void)printf(\t\tdo some operations here.\n”);
    (void)printf(\t\tleave foo(scoped_ptr).\n”);
    }
    void foo(boost::shared_ptr<MyClass>) {
      (void)printf(\t\tenter foo(shared_ptr).\n”);
      (void)printf(\t\tdo some operations here.\n”);
    (void)printf(\t\tleave foo(shared_ptr).\n”);
    }

    Finally a test function and main:

    void test() {
      (void)printf(\tenter test().\n”);

    std::auto_ptr<MyClass> ptrAuto(new MyClass);
      (void)printf(“\ttest() – calling foo(auto_ptr).\n”);
      foo(ptrAuto);
      (void)printf(“\ttest() – foo(auto_ptr) finished.\n\n”);

      boost::scoped_ptr<MyClass> ptrScoped(new MyClass);
      foo(ptrScoped);

      boost::shared_ptr<MyClass> ptrShared(new MyClass);
      (void)printf(“\ttest() – calling foo(shared_ptr).\n”);
      foo(ptrShared);
      (void)printf(“\ttest() – calling foo(shared_ptr finished.\n\n”);

    (void)printf(\tleave test().\n”);
    }
    int main(int argc, char *argv[])
    {
      (void)printf(“main – calling test().\n”);
      test();
      (void)printf(“main – test() finished.\n”);
      return 0;
    }

    The first thing you will notice when trying to compile this (or did you notice while reading the code?) is that void foo(boost::scoped_ptr<MyClass>) is dead in the water. The compiler will refuse to compile it and complain about not being able to access the privately declared copy constructor in scoped_ptr. This is the way this smart pointer enforces its rule that it cannot transfer ownership! Passing objects by value always forces the object passed to to be copied  from the object passed in in order to be created.

    So after you remove the declaration of the scoped_ptr and the call to foo(scoped_ptr) you will be able to compile it. Run it and you will get the following output:

    main - calling test().
            enter test().
    >> MyClass constructed <<
            test() - calling foo(auto_ptr).
                    enter foo(auto_ptr).
                    do some operations here.
                    leave foo(auto_ptr).
    >> MyClass destructed <<
            test() - foo(auto_ptr) finished.

    >> MyClass constructed <<
            test() - calling foo(shared_ptr).
                    enter foo(shared_ptr).
                    do some operations here.
                    leave foo(shared_ptr).
            test() - foo(shared_ptr) finished.

            leave test().
    >> MyClass destructed <<

    main - test() finished.

    Look carefully at the moments MyClass is constructed and destructed. Both times MyClass is newed in our test() function. When the pointer to MyClass is contained in an auto_ptr, it is deleted the moment the last auto_ptr holding ownership of it isn’t needed anymore: the moment we leave the scope of foo(auto_ptr).

    The moment of destruction is different when the pointer is contained in a shared_ptr. MyClass only gets deleted when there is no more shared_ptr referencing it: the moment we leave the scope of test()! The reason for this is that MyClass is freed when the internal reference count of the shared_ptr reaches zero.

    Reference counting is done in the constructor and destructor of the shared pointer. Upon construction the reference counter is set to one. When it is passed by value (i.e. another shared_ptr gets copy-constructed) to foo(shared_ptr), the reference counter goes up to two. As soon as we leave that function, the destructor decreases the reference counter by one. And when we leave the test() function, the destructor of the shared_ptr  inside the scope of that function will decrease the reference count by one to zero. MyClass is not referenced anymore and the destructor will finally delete it. Due to this behavior, the boost::shared_ptr can be properly used with (STL) containers.

    Shared pointers can be pretty useful as members of a class, for example when you are making use of the pimpl idiom.

    Like the boost::scoped_ptr, the boost::shared_ptr cannot correctly hold a pointer to a dynamically allocated array. Use the boost::shared_array for this purpose.

    A special note has to be made on passing smart pointers on to functions:

    void f(boost::shared_ptr<int>, int);
    int g();
    void ok() {
    boost::shared_ptr<int> p(new int(2));
    f(p,g());
    }
    void bad() {
      f(shared_ptr<int>(new int(2)), g());
    }

    The bad() functions constructs a temporary shared_ptr in place, creating the possibility of a memory leak. Function arguments are evaluated in unspecified order, making it possible to evaluate new int(2) first, followed by g() which might throw an exception causing the shared_ptr never to be constructed and new int(2) never to be freed.

    See also Herb Sutter’s treatment on this topic.

    More C# Articles
    More By J. Nakamura


     

    C# ARTICLES

    - Working with Dates and Times in C#
    - Generics, Dictionaries, and More
    - More About Generics
    - Working with C# Collections
    - Generics
    - C# and XML
    - Pointers and Arrays in C#
    - C# 3.0 Extension Methods
    - Overloading Operators in C#
    - Iterators and Nullable Types
    - Patterns and Iterators in C#
    - C# Exceptions
    - Methods in C#
    - Delegates and Events in C#
    - Advanced C#

     
    Best Practices for Windows Vista Migration Presentation
    Dell and Microsoft recently held a series of face-to-face seminars entitled, &qu....

     
    Creating a Culture for Code Reuse
    If you oversee development teams you know that like it or not proprietary and ex....

     
    Keys to Web Application Acceleration: Advances in Delivery Systems
    Accelerate Web apps by up to 5x. Ensure significantly faster access to the Web a....

     
    Optimizing Application Monitoring
    Tired of finding out from your customers that you're offline? This white paper e....

     
    Solaris to Solaris Migration -- Migrating applications from Sun SPARC to Dell PowerEdge R900
    This comprehensive Migration Guide reviews the approach that Principled Technolo....

     




    © 2003-2009 by Developer Shed. All rights reserved. DS Cluster 5 hosted by Hostway
    Stay green...Green IT