20130114

A Quick Reminder About shared_ptr constness

Short blog here, just pointing out a weird problem I ran into the other day in the handling of shared_ptrs. I have some classes that keep shared_ptr members, and sometimes I need to hand out more references to callers... you know, share them. That getter might look a bit like this:

class Klass
{
    public:
    shared_ptr<int> GetX() { return x; }
    const shared_ptr<int> GetX() const { return x; }

    shared_ptr<int> x;
};

Right? Looks good? That's the normal way I write my pointers, anyway. But... there's something wrong here, and maybe you've already spotted it. Here's the code that triggers it, anyway.

int __cdecl wmain(int argc, wchar_t* argv[])
{
    Klass k;
    k.x = shared_ptr<int>(new int(3));

    const Klass* pk = &k;
    shared_ptr<int> spX(pk->GetX()); // invokes const GetX()

    *spX = 13;
    wprintf(L"x: %d\n", *spX); // x: 13

    return 0;
}

Hey, wait a second! This invokes the const getter, but then the caller is able to modify the value. How did that circumvent the const? Well, the problem is that you returned a const shared_ptr<int> value, pointing to a non-const int, so the shared_ptr object can't be modified, but the thing it points to can. Moreover, since it's returning a value (rather than a pointer), the const doesn't even matter.

The fix is simple. Here ya go:

shared_ptr<const int> GetX() const { return x; }

// and later in wmain()

shared_ptr<const int> spX(pk->GetX()); // invokes const GetX()

Now we get a compiler error, as we want:

main.cpp(35) : error C3892: 'spX' : you cannot assign to a variable that is const

This difference is analogous to the difference in constness on raw pointer types: int* const vs const int* (same as int const*). These rules don't seem very inuitive or nice, but you should know them if you're trying to make your code correct.

1 comments:

Beyamor said...

legeeeit

Post a Comment