8

Details

I found some information about the Null Object Pattern here (https://softwareengineering.stackexchange.com/questions/152094/null-pointers-vs-null-object-pattern) and here (http://en.wikipedia.org/wiki/Null_Object_pattern#C.2B.2B).

However, the C++ implementation doesn't illustrate my use case.

I also saw the related link for Nullable Type (http://en.wikipedia.org/wiki/Nullable_type).

Use Case

I have an object that is not part of a hierarchy and wouldn't normally be allocated on the heap. Furthermore, there isn't a convenient value that can be used as a sentinel to indicate null. Hopefully, the following code makes the use case clear.

class ContrivedType
{
public:
    ContrivedType() :
        mValue(0)
    {
        // Do nothing
    }

    bool operator==(const ContrivedType& other) const
    {
        return mValue == other.mValue;
    }

    void setValue(std::uint16_t value)
    {
        mValue = value;
    }

private:
    // All values in the range [0, 65535] are valid for use
    std::uint16_t mValue;
};

class Foo
{
public:
    const ContrivedType getValue() const
    {
        return mValue;
    }

    void setValue(const ContrivedType &value)
    {
        mValue = value;
    }

private:
    ContrivedType mValue;
};

int main()
{
    Foo f;

    if (f.getValue() == ContrivedType())
    {
        // Ambiguous case
        // -    Was this value explicitly set to be the same value
        //      as when it's default constructed
        // OR
        // -    Was the value never set
    }

    return 0;
}

Possible Solution 1

Force users of the ContrivedType that need to disambiguate between the default state and unset to use pointers and dynamically allocate the ContrivedType. Perhaps something like this?

class Foo
{
public:
    Foo() :
        mValue(nullptr)
    {
        // Do nothing
    }

    const ContrivedType* getValue() const
    {
        return mValue.get();
    }

    void setValue(const ContrivedType &value)
    {
        if (!mValue)
        {
            mValue.reset(new ContrivedType(value));
        }
        else
        {
            *mValue = value;
        }
    }

private:
    std::unique_ptr<ContrivedType> mValue;
};

Now it's very clear whether the ContrivedType was set or not.

Possible Solution 2

Update the implementation of the ContrivedType to support the concept of null.

class ContrivedType
{
public:
    ContrivedType() :
        mState(nullptr)
    {
        // Do nothing
    }

    explicit ContrivedType(std::uint16_t value) :
        mState(&mStorage)
    {
        mStorage.mValue = value;
    }

    bool isNull() const
    {
        return mState == nullptr;
    }

    bool operator==(const ContrivedType& other) const
    {
        if (!isNull())
        {
            return mStorage.mValue == other.mStorage.mValue;
        }
        else
        {
            return other.isNull();
        }
    }

    void setValue(std::uint16_t value)
    {
        mStorage.mValue = value;

        if (!mState)
        {
            mState = &mStorage;
        }
    }

private:
    struct State
    {
        // All values in the range [0, 65535] are valid for use
        std::uint16_t mValue;
    };

    State mStorage;

    // This will point to the storage when a value actually set
    State* mState;
};

Question

Is there an established pattern or idiom for this concept? If not are there any recommendations for implementing it?

Rationale

In the real code there are classes with 1 ore more members which are optional in some contexts. These classes are being serialized over a socket using a protocol that supports fields that are missing (i.e., the optional fields). Instead of wasting bytes serializing a default constructed object that wasn't explicitly set the serialization could skip over the optional fields. For example, an updateFoo(const Foo&) function. If only a subset of an existingFoo instance is being updated then only those fields need to be serialized.

Edit

It looks like std::experimental::optional (brought to my attention by @myaut) is what I would want to use but I don't have access to it.

For now I would need to use a solution that would work with Visual Studio 2013 (2015 is probably okay) and g++ 4.8.

13
  • Probably you should take a look at std::optional Commented Apr 5, 2015 at 18:26
  • @myaut Thank you, I'm not familiar this but I will look into it. Commented Apr 5, 2015 at 18:27
  • 3
    I think you don't see this pattern implemented in C++ is because it's not needed. in Java and C# , it is very common to return null as an invalid result. since everything in Java/C# is allocated in the heap (even primitives are wrapped automatically as object) , null can be returned from every function. in C++ , it is not possible to return null on functions that don't return a pointer. you must throw an exception or handle the invalidness in some other way than to return null. this is way C++ developers do not return null object- simply because C++ handle invalidness by other means . Commented Apr 5, 2015 at 18:55
  • 1
    @DavidHaim I'm not trying to assert you're wrong by asking the following questions, I'm just curious. What is the point of std::optional if this isn't needed in C++? I definitely want to know the distinction so should I handle this in C++? Are you suggesting Option 1? Commented Apr 5, 2015 at 19:00
  • 1
    @DavidHaim: Actually even in Java this may be considered harmful (i.e. Robert Martin opposes to that in his "Clean Code" book). Commented Apr 5, 2015 at 19:54

1 Answer 1

4

From this question (think to upvote it ;):

std::experimental::optional originates from the Boost.Optional library, and this implementation works well in Visual C++ 12.0 (though it differs a little). Reference single-header implementation, based on the N3793 proposal paper, can be found here.

The latest list of supported C++11/14/1z core and library features that are shipped with Visual Studio can be found from the Visual C++ Team blog, from this post in particular. A set of header files of the Standard Library implementation (and some extensions) from Microsoft can be viewed here.

I had it a taste recently, with a bit of effort for building it, I manage to use it and was happy with it. Hope it helps.

Sign up to request clarification or add additional context in comments.

2 Comments

I ended up implementing my own Optional class.
@JamesAdkison That's great! you could answer your own question with your implementation of Optional :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.