Click here to Skip to main content
15,892,005 members
Articles / Programming Languages / C++

Smart Pointers to boost your code

Rate me:
Please Sign up or sign in to vote.
4.93/5 (122 votes)
27 Sep 2004CPOL13 min read 1.1M   2.5K   227  
A beginner's introduction to the smart pointers provided by the boost library.
// boostspsample.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include "boost/smart_ptr.hpp"
#include <vector>


// ==================================================================
//  CSample::
// ------------------------------------------------------------------
///
/// A class that echoes construction / destruction to the console.
/// This will help us seeing what happens
/// 
class CSample
{
protected:
    int m_n;    ///< helps identify different instances

    static int NewInstanceID; 

public:
    CSample()       { m_n = ++NewInstanceID;  printf("constructing CSample(%i)\n", m_n); }
   ~CSample()       { printf("destroying CSample(%i)\n", m_n);   }

    bool Query() { printf("CSample(%i)::Query - returning true \n", m_n); return true; }
    void Use() { printf("CSample(%i)::Use\n", m_n);  }
};
typedef boost::shared_ptr<CSample> CSamplePtr;


int CSample::NewInstanceID = 0;



// ==================================================================
//  Sample1_ScopedPtr
// ------------------------------------------------------------------
///
/// Sample: scoped_ptr  - automatic destruction on exit
/// 
void Sample1_ScopedPtr()
{
    boost::scoped_ptr<CSample> pSample(new CSample);
    if (!pSample->Query() )
        return;

    pSample->Use();
}

// ==================================================================
//  Sample1_Plain
// ------------------------------------------------------------------
///
/// Sample: PLain Pointer counterpart for Sample1_ScopedPtr
/// 
void Sample1_Plain()
{
    CSample * pSample = new CSample;
    if (!pSample->Query() )
    {
        delete pSample;
        return;
    }

    pSample->Use();
    delete pSample;
}


// ==================================================================
//  boost::Sample2_Shared
// ------------------------------------------------------------------
///
/// demonstrates basic use of shared_ptr
/// 
void Sample2_Shared()
{
  // (A) create a new CSample instance with one reference
  boost::shared_ptr<CSample> mySample(new CSample); 
  printf("The Sample now has %i references\n", mySample.use_count()); // should be 1

  // (B) assign a second pointer to it:
  boost::shared_ptr<CSample> mySample2 = mySample; // should be 2 refs by now
  printf("The Sample now has %i references\n", mySample.use_count());

  // (C) set the first pointer to NULL
  mySample.reset(); 
  printf("The Sample now has %i references\n", mySample2.use_count());  // 1

  // the object allocated in (1) is deleted automatically when mySample2 goes out of scope
}


// ==================================================================
//  boost::Sample3_Container
// ------------------------------------------------------------------
///
/// demonstrates basic use of shared_ptr
/// 
void Sample3_Container()
{
  typedef boost::shared_ptr<CSample> CSamplePtr;

  // (A) create a container of CSample pointers:
  std::vector<CSamplePtr> vec;

  // (B) add two elements
  printf("adding three elements to a vector...\n");
  vec.push_back(CSamplePtr(new CSample));
  vec.push_back(CSamplePtr(new CSample));
  vec.push_back(CSamplePtr(new CSample));

  // (C) "keep" a pointer to the second: 
  printf("keeping a reference to the second...\n"); 
  CSamplePtr anElement = vec[1];

  // (D) destroy the vector:
  printf("destroying the vector releases it's elements...\n");
  vec.clear();

  // (E) the second element still exists
  printf("referenced elements still exist, however...\n");
  anElement->Use();
  printf("done. cleanup is automatic\n");

  // (F) anElement goes out of scope...
}



// ==================================================================
//  boost::Sample4_NeedForWeak
// ------------------------------------------------------------------

struct CDad;
struct CChild;

typedef boost::shared_ptr<CDad>   CDadPtr;
typedef boost::shared_ptr<CChild> CChildPtr;


struct CDad : public CSample
{
   CSamplePtr myBoy;
   void SetBeer() { printf("Dad(%i) happy!\n", m_n); }
};

struct CChild : public CSample
{
  CDadPtr myDad;
  void BringBeer() { myDad->SetBeer(); }

};


///
/// deliberately creates a circular reference, and resolves it manually
/// 
void Sample4_NeedForWeak()
{

    // a "thing" that holds a smart pointer to another "thing":

    CDadPtr   parent(new CDad); 
    CChildPtr child(new CChild);

    // deliberately create a circular reference:
    parent->myBoy = child; 
    child->myDad = parent;


    // resetting one ptr...
    child.reset();

    // parent.reset() - this would leak both objects!
    // we resolve this manually:
    parent->myBoy.reset();
    parent.reset();
}

// ==================================================================
//  boost::Sample5_Using weak_ptr
// ------------------------------------------------------------------

struct CBetterChild : public CSample
{
    boost::weak_ptr<CDad> myDad;

    void BringBeer() 
    { 
        CDadPtr strongDad = myDad.lock(); // request a strong pointer to the parent object
        if (strongDad)  // object still exists?
        {
            strongDad->SetBeer();
        }
        else
        {
            printf("Child(%i): Out of Dad\n", m_n);
        }
    }
};
typedef boost::shared_ptr<CBetterChild> CBetterChildPtr;


void Sample5_Using_weak_ptr()
{
    printf("Parent: "); 
    CDadPtr         parent(new CDad); 

    printf("Child:  "); 
    CBetterChildPtr child(new CBetterChild);

    parent->myBoy = child;
    child->myDad = parent;

    // ...

    printf("Bring beer to existing dad...\n");
    child->BringBeer();

    printf("set dad to NULL\n");
    parent.reset();

    printf("now, we cannot bring this dad beer anymore..\n");
    child->BringBeer();

}




extern "C" int getch();

int main(int argc, char* argv[])
{
    printf("\n *** Sample 1: using plain pointers\n");
    Sample1_Plain();

    printf("\n *** Sample 1: using scoped_ptr\n");
    Sample1_ScopedPtr();

    printf("\n *** Sample 2: basic shared_ptr\n");
    Sample2_Shared();

    printf("\n *** Sample 3: vector of shared_ptr\n");
    Sample3_Container();

    printf("\n *** Sample 4: vector of shared_ptr\n");
    Sample4_NeedForWeak();

    printf("\n *** Sample 5: using weak_ptr\n");
    Sample5_Using_weak_ptr();

    getch();
    return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Klippel
Germany Germany
Peter is tired of being called "Mr. Chen", even so certain individuals insist on it. No, he's not chinese.

Peter has seen lots of boxes you youngsters wouldn't even accept as calculators. He is proud of having visited the insides of a 16 Bit Machine.

In his spare time he ponders new ways of turning groceries into biohazards, or tries to coax South American officials to add some stamps to his passport.

Beyond these trivialities Peter works for Klippel[^], a small german company that wants to make mankind happier by selling them novel loudspeaker measurement equipment.


Where are you from?[^]



Please, if you are using one of my articles for anything, just leave me a comment. Seeing that this stuff is actually useful to someone is what keeps me posting and updating them.
Should you happen to not like it, tell me, too

Comments and Discussions