Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8359613
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 9, 20262026-06-09T11:12:02+00:00 2026-06-09T11:12:02+00:00

I came accross an intriguing implementation of a base class on the C++ FAQ

  • 0

I came accross an intriguing implementation of a base class on the C++ FAQ that, according to my naive understanding, could serve as an alternative to some of the smart pointer implementations (e.g. shared_ptr). Here’s the example code verbatim, but please follow the link above for an explanation:

class Fred {
public:

  static Fred create1(std::string const& s, int i);
  static Fred create2(float x, float y);

  Fred(Fred const& f);
  Fred& operator= (Fred const& f);
 ~Fred();

  void sampleInspectorMethod() const;   // No changes to this object
  void sampleMutatorMethod();           // Change this object

  ...

private:

  class Data {
  public:
    Data() : count_(1) { }
    Data(Data const& d) : count_(1) { }              // Do NOT copy the 'count_' member!
    Data& operator= (Data const&) { return *this; }  // Do NOT copy the 'count_' member!
    virtual ~Data() { assert(count_ == 0); }         // A virtual destructor
    virtual Data* clone() const = 0;                 // A virtual constructor
    virtual void sampleInspectorMethod() const = 0;  // A pure virtual function
    virtual void sampleMutatorMethod() = 0;
  private:
    unsigned count_;   // count_ doesn't need to be protected
    friend class Fred; // Allow Fred to access count_
  };

  class Der1 : public Data {
  public:
    Der1(std::string const& s, int i);
    virtual void sampleInspectorMethod() const;
    virtual void sampleMutatorMethod();
    virtual Data* clone() const;
    ...
  };

  class Der2 : public Data {
  public:
    Der2(float x, float y);
    virtual void sampleInspectorMethod() const;
    virtual void sampleMutatorMethod();
    virtual Data* clone() const;
    ...
  };

  Fred(Data* data);
  // Creates a Fred smart-reference that owns *data
  // It is private to force users to use a createXXX() method
  // Requirement: data must not be NULL

  Data* data_;   // Invariant: data_ is never NULL
};

Fred::Fred(Data* data) : data_(data)  { assert(data != NULL); }

Fred Fred::create1(std::string const& s, int i) { return Fred(new Der1(s, i)); }
Fred Fred::create2(float x, float y)            { return Fred(new Der2(x, y)); }

Fred::Data* Fred::Der1::clone() const { return new Der1(*this); }
Fred::Data* Fred::Der2::clone() const { return new Der2(*this); }

Fred::Fred(Fred const& f)
  : data_(f.data_)
{
  ++data_->count_;
}

Fred& Fred::operator= (Fred const& f)
{
  // DO NOT CHANGE THE ORDER OF THESE STATEMENTS!
  // (This order properly handles self-assignment)
  // (This order also properly handles recursion, e.g., if a Fred::Data contains Freds)
  Data* const old = data_;
  data_ = f.data_;
  ++data_->count_;
  if (--old->count_ == 0) delete old;
  return *this;
}

Fred::~Fred()
{
  if (--data_->count_ == 0) delete data_;
}

void Fred::sampleInspectorMethod() const
{
  // This method promises ("const") not to change anything in *data_
  // Therefore we simply "pass the method through" to *data_:
  data_->sampleInspectorMethod();
}

void Fred::sampleMutatorMethod()
{
  // This method might need to change things in *data_
  // Thus it first checks if this is the only pointer to *data_
  if (data_->count_ > 1) {
    Data* d = data_->clone();   // The Virtual Constructor Idiom
    --data_->count_;
    data_ = d;
  }
  assert(data_->count_ == 1);

  // Now we "pass the method through" to *data_:
  data_->sampleMutatorMethod();
}

I don’t see this approach being used in any C++ libraries; although it seems quite elegant. Assuming a single-threaded environment, for the sake of simplicity, please answer the following questions:

  1. Is this a suitable alternative to the smart pointer approach for managing the lifetime of objects, or is it just asking for trouble?
  2. If it is suitable, why do you suppose it’s not used more often?
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-09T11:12:04+00:00Added an answer on June 9, 2026 at 11:12 am

    Is this a suitable alternative to the smart pointer approach for managing the lifetime of objects, or is it just asking for trouble?

    No, I don’t think it’s a good idea to reinvent reference counting especially since we have std::shared_ptr now in C++11. You can easily implement your possibly polymorphic reference-counted Pimpl idiom class in terms of std::shared_ptr. Notice how we don’t have to implement copy ctor, assignment, dtor anymore and mutation gets simpler w.r.t. the reference counter and cloning:

    // to be placed into a header file ...
    
    #include <memory>
    #include <utility>
    #include <string>
    
    class Fred
    {
    public:
        static Fred create1(std::string const& s, int i);
        static Fred create2(float x, float y);
    
        void sampleInspectorMethod() const;   // No changes to this object
        void sampleMutatorMethod();           // Change this object
    
    private:
        class Data;
        std::shared_ptr<Data> data_;
    
        explicit Fred(std::shared_ptr<Data> d) : data_(std::move(d)) {}
    };
    

    …and the implementation…

    // to be placed in the corresponding CPP file ...
    
    #include <cassert>
    #include "Fred.hpp"
    
    using std::shared_ptr;
    
    class Fred::Data
    {
    public:
        virtual ~Data() {}                               // A virtual destructor
        virtual shared_ptr<Data> clone() const = 0;      // A virtual constructor
        virtual void sampleInspectorMethod() const = 0;  // A pure virtual function
        virtual void sampleMutatorMethod() = 0;
    };
    
    namespace {
    
    class Der1 : public Fred::Data
    {
    public:
        Der1(std::string const& s, int i);
        virtual void sampleInspectorMethod() const;
        virtual void sampleMutatorMethod();
        virtual shared_ptr<Data> clone() const;
        ...
    };
    
    // insert Der1 function definitions here
    
    class Der2 : public Data
    {
    public:
        Der2(float x, float y);
        virtual void sampleInspectorMethod() const;
        virtual void sampleMutatorMethod();
        virtual shared_ptr<Data> clone() const;
        ...
    };
    
    // insert Der2 function definitions here
    
    } // unnamed namespace
    
    Fred Fred::create1(std::string const& s, int i)
    {
        return Fred(std::make_shared<Der1>(s,i));
    }
    
    Fred Fred::create2(float x, float y)
    {
        return Fred(std::make_shared<Der2>(x,y));
    }
    
    void Fred::sampleInspectorMethod() const
    {
        // This method promises ("const") not to change anything in *data_
        // Therefore we simply "pass the method through" to *data_:
        data_->sampleInspectorMethod();
    }
    
    void Fred::sampleMutatorMethod()
    {
        // This method might need to change things in *data_
        // Thus it first checks if this is the only pointer to *data_
        if (!data_.unique()) data_ = data_->clone();
        assert(data_.unique());
    
        // Now we "pass the method through" to *data_:
        data_->sampleMutatorMethod();
    }
    

    (untested)

    If it is suitable, why do you suppose it’s not used more often?

    I think reference counting, if you implement it yourself, is easier to get wrong. It also has the reputation of being slow in multithreaded environments because the reference counters have to be incremented and decremented atomically. But I guess due to C++11 which offers shared_ptr and move semantics, this copy-on-write pattern might get a bit more popular again. If you enable move semantics for the Fred class you can avoid some of the costs of atomically incrementing reference counters. So moving a Fred object from one location to another should be even faster than copying it.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I am reading through some code in AQGrid and came accross: @protocol AQGridViewDataSource; @class
I'm reviewing some old python code and came accross this 'pattern' frequently: class Foo(object):
I came accross a very strange problem with tr1::regex (VS2008) that I can't figure
I came accross a weird problem, I want to do some basic math checks.
I just came accross a site that has been hacked and I'm wondering what
I came accross several questions where answers state that using T* is never the
I was brushing up (not homework)on some computation-theory and came accross this problem: How
Here is some code I came accross for logging in but how would you
I am trying to monitor tomcat with the MBeanUtil class,I came accross the ResourceCache
Just came accross this today in a Spring MVC cotnroller class, @RequestMapping(value = {

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.