如何实现null对象?

时间:2015-04-05 18:20:51

标签: c++

详细

我在这里找到了一些关于空对象模式的信息(https://softwareengineering.stackexchange.com/questions/152094/null-pointers-vs-null-object-pattern)和这里(http://en.wikipedia.org/wiki/Null_Object_pattern#C.2B.2B)。

但是,C ++实现并没有说明我的用例。

我还看到了 Nullable Type http://en.wikipedia.org/wiki/Nullable_type)的相关链接。

用例

我有一个不属于层次结构的对象,通常不会在堆上分配。此外,没有一个方便的值可以用作标记 null 的标记。希望以下代码能够清楚地说明用例。

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;
}

可能的解决方案1 ​​

强制需要消除默认状态和取消设置之间歧义的ContrivedType用户使用指针并动态分配ContrivedType。也许是这样的?

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;
};

现在很清楚ContrivedType是否已设定。

可能的解决方案2

更新ContrivedType的实施以支持 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;
};

问题

这个概念是否有既定的模式或成语?如果没有任何实施建议?

原理

在实际代码中,在某些上下文中有一些包含1个或更多成员的类 optional 。这些类使用支持缺失字段的协议(即可选字段)在套接字上进行序列化。序列化可以跳过可选字段,而不是浪费字节序列化未明确设置的默认构造对象。例如,updateFoo(const Foo&)函数。如果仅更新现有Foo实例的子集,则只需要序列化这些字段。

修改

看起来像std::experimental::optional(@myaut提请我注意)是我想要使用但我无法访问它。

现在我需要使用一个可以与Visual Studio 2013(2015年可能还可以)和g ++ 4.8一起使用的解决方案。

1 个答案:

答案 0 :(得分:2)

this question开始(想到赞成它):

  

std::experimental::optional源自Boost.Optional库,此实现在Visual C ++ 12.0中运行良好(尽管它不同a little)。可以找到基于N3793提案文件的参考单页头实施here

     

Visual Studio附带的受支持的C ++ 11/14 / 1z核心和库功能的最新列表可以从Visual C++ Team blog,特别是this post中找到。可以查看Microsoft的标准库实现(以及一些扩展)的一组头文件here

我最近尝到了它的味道,为了构建它我付出了一些努力,我设法使用它,并对它很满意。希望它有所帮助。