Details
我找到了一些关于空对象模式 here (https://softwareengineering.stackexchange.com/questions/152094/null-pointers-vs-null-object-pattern https://softwareengineering.stackexchange.com/questions/152094/null-pointers-vs-null-object-pattern) 和这里 (http://en.wikipedia.org/wiki/Null_Object_pattern#C.2B.2B http://en.wikipedia.org/wiki/Null_Object_pattern#C.2B.2B).
然而,C++ 实现并没有说明我的用例。
我还看到了相关链接可空类型 (http://en.wikipedia.org/wiki/Nullable_type http://en.wikipedia.org/wiki/Nullable_type).
Use Case
我有一个不属于层次结构的对象,通常不会在堆上分配。此外,没有一个方便的值可以用作哨兵来指示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
需要消除默认状态和unset使用指针并动态分配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;
};
Question
这个概念有既定的模式或习语吗?如果没有,有什么实施建议吗?
基本原理
在真实的代码中,有一些类有 1 个或多个成员,它们是optional在某些情况下。这些类通过套接字使用支持字段的协议进行序列化missing(即可选字段)。序列化可以跳过序列化未显式设置的默认构造对象,而不是浪费字节optional字段。例如,一个updateFoo(const Foo&)
功能。如果只是现有的一个子集Foo
实例正在更新,那么只有那些字段需要序列化。
Edit
看起来像std::experimental::optional
(由 @myaut 引起我的注意)是我想要使用的,但我无权访问它。
现在我需要使用一个适用于 Visual Studio 2013(2015 可能还可以)和 g++ 4.8 的解决方案。