Const Constructors

If you’re a regular reader — and I’m pretty sure you’re not — you may have seen my infamous “craptimizing” articles: one and two. Read them if you like, but the short story is that I thought I had discovered a neat way to optimize using const member functions. Of course, there was a problem.

My approach is still flawed, but tonight I had an “ah-ha” moment. Suddenly, I knew what was missing — what had put the “crap” in “craptimizing”. What I really needed was a const constructor.

In today’s C++, during construction, we have no way of knowing if we are creating a regular ‘ole Foo, or a const Foo. But with a const constructor, I could differentiate:


#include <iostream>
#include <stdexcept>

using namespace std;

template 
class Foo {
    private:
        bool initialized_;
        T data_;
    public:
        Foo() :
            initialized_( false )
        {}

        Foo( T data ) const :
            initialized_( true ),
            data_( data )
        {}

        void set( int data )
        {
            data_ = data;
            initialized_ = true;
        }

        void fubarize()
        {
            if( !initialized_ )
                throw invalid_argument( "Uninitialized Foo" );

            cout << "Called slow fubarize()" << endl;
        }

        void fubarize() const
        {
            // No initialized_ check required.
            // It's important to fubarize quickly.
            cout << "Called fast fubarize()" << endl;
        }
};

int main()
{
    Foo f;

    try
    {
        f.fubarize();   // Will throw invalid_argument
    }
    catch( invalid_argument &e )
    {
        cout << e.what() << endl;
    }

    f.set( 42 );
    f.fubarize();   // OK, calls slow fubarize()

    const Foo cf1( 42 );
    cf.fubarize();  // OK, calls fast fubarize()

    const Foo cf2;  // Error! (This is good)
}

Note that even if we exclusively used const Foos in our program, the compiler could not perform this optimization (omitting the initialized check) without our help. In short, this is because there are precious few circumstances under which the compiler can actually trust the const qualifier. If you want more details, you got ’em.

Alas, I don’t think there is any reasonable way to get this behavior with standard C++. (To me, separate “Foo” and “ConstFoo” classes is unreasonable.) And, to make matters worse, adding this feature would break lots of existing code, because the status quo is:


const Foo cf;  // Calls Foo::Foo()

This obviously works fine: how else would we create a const Foo?

PS:
Google finds tons of references to “const constructor”. One very interesting document was this ISO/IEC Discussion Draft by Kevlin Henny. His proposal is notable in that it manages not to break backwards compatibility.

Advertisements

3 Responses to “Const Constructors”


  1. 1 Hillary October 26, 2005 at 6:08 pm

    Ok Mark. I am commenting on your entry. I feel it was a little bit on the boring side. I recommend throwing in a comparison now and then, such as, C++ and Oprah, or C++ and chocolate cake. I would really like if you could do that from now on. Thank you.

  2. 2 Bheeshmar October 28, 2005 at 12:18 pm

    Why are two classes untenable? You have two distinct behaviors. One could even be implemented in terms of the other:

    class ReadOnlyFoo
    {
    public:
    ReadOnlyFoo( const T … ) {}
    void fubarize() const { … }
    };

    class ReadWriteFoo
    {
    public:
    ReadWriteFoo() rofPtr(0) {}
    ~ReadWriteFoo() { delete rofPtr; }
    void set(const T value) { rofPtr= new RoadOnlyFoo(value); }
    void fubarize() { if( rofPtr ) rofPtr->fubarize(); else throw … ; }
    private:
    ReadOnlyFoo * rofPtr;
    };

  3. 3 Mark October 28, 2005 at 5:06 pm

    For me, separate classes give off a strong code-smell. With your solution, client code could do confusing stuff like:
    const ReadWriteFoo crwf;
    mutable ReadOnlyFoo mrof;

    If you haven’t read Kevlin’s proposal, I highly recommend it, because he gives several “real world” use cases for const constructors.


Comments are currently closed.




%d bloggers like this: