Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Gamasutra: The Art & Business of Making Gamesspacer
arrowPress Releases








If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

Using Mutable To Write Better Container Code

by Neil Gower on 10/07/09 03:10:00 pm   Expert Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 
// Ever wondered what the keyword "mutable" is for? Been annoyed by duplicate
// functions while trying to write const-correct code? This might be what you
// need...

class MyContainer {
public:
    // Suppose we've got a container class that holds some objects...
    struct MyObject {};

private:
    // The objects could be stored in a regular array, like this.
    MyObject contents[10];

    // Or, you can declare the contents mutable. This means the array is never
    // treated as a const member, even if "this" is a const pointer (such as
    // inside a const member function)

    mutable MyObject mutableContents[10];

public:
    // For example, this lookup() method is declared const, and it is const
    // in the sense that it doesn't change the container. However, it returns
    // objects from the container as non-const, so the objects *can* be
    // changed...

    MyObject& lookup( size_t idx ) const {
        // Illegal! All members are treated as const in a const method, and
        // you can't convert from const to non-const to return it.
        //return contents[idx];


        // but mutable is okay...
        return mutableContents[idx];
    }
    // Does this violate what it means for the container to be const?
    //
    // That's up to you and the design of your class. Maybe it doesn't matter
    // to the const-ness of the container what the values of the objects are.
    // Usually however, we want to be more strict...

    // If you don't want the contents of a const container to be changeable,
    // you could implement the lookups as a pair of functions like
    // strictLookup(), below.

    MyObject& strictLookup( size_t idx ) {
        return lookup(idx);
    }

    // What's nice about this approach is that you don't have two copies of
    // the lookup code (which in this example is trivial, but wouldn't be in
    // a real container). Both the const and non-const versions of
    // strictLookup() can share lookup(), because it is a const method
    // accessing a mutable data member.
    //
    // BTW - A properly strict version of this class would also make lookup()
    //     private.

    const MyObject& strictLookup( size_t idx ) const {
        return lookup(idx);
    }

    // The catch with using mutable is that the compiler won't stop *you*
    // from changing the mutable members of your class inside your const
    // methods, which you probably don't want to do. So using mutable
    // requires some care.
    //
    // What about const_cast? Sadly, const_cast isn't guaranteed to work if
    // the container itself was declared const. For example, the compiler is
    // allowed to put a const container in a special read-only memory area
    // (if such a thing exists on your platform), which would cause
    // const_cast to fail at run-time. Proper uses of const_cast are few and
    // far between, and this isn't one of them.

};


// So to summarize...
int main( void ) {
    MyContainer c;
    // cc is just a reference to the container c, that treats it as const.
    const MyContainer& cc( c );

    // We can access container contents without restriction going through
    // lookup(), even though it is a const method...

    MyContainer::MyObject& a = c.lookup( 1 );
    MyContainer::MyObject& b = cc.lookup( 2 );

    // But using strictLookup(), we can't get a non-const object reference
    // out of a const container.

    MyContainer::MyObject& x = c.strictLookup( 3 );
    // illegal!
    //MyContainer::MyObject& y = cc.strictLookup( 4 );

    const MyContainer::MyObject& y = cc.strictLookup( 4 );

    return 0;
}

// Code with prose snippets, instead of prose with code snippets. Like it?
// Hate it? Wish the whole thing was in assembly?

Related Jobs

Ubisoft RedLynx
Ubisoft RedLynx — Helsinki, Finland
[05.24.19]

Senior/Lead Graphics Programmer
PixelPool
PixelPool — Portland, Oregon, United States
[05.23.19]

Backend Developer ?(Unreal Engine 4, Blueprint, C++)
Petroglyph Games
Petroglyph Games — Las Vegas, Nevada, United States
[05.23.19]

Senior Game Engineer (C++)
Sanzaru Games Inc.
Sanzaru Games Inc. — Foster City , California, United States
[05.23.19]

Junior Gameplay Engineer





Loading Comments

loader image