我正在用c ++实现分布式地图并寻找一个好的API设计。 第一个和直接的选择是使它完全像std :: map。问题在于迭代器。
IMap<std::string,Person>::iterator it;
it = map.find("sample");
if(it == map.end() ){
//NULL
}
for(it = map.begin(); it != map.end(); it++){
//iterate
}
在分布式上下文中(至少在我正在实现的上下文中),没有地图的开头和结尾。它不是以任何方式排序的,因此返回迭代器似乎不是一个选项。
第二个选项是按副本返回值类,如下所示:
Person emptyPerson;
Person person = map.get("sample");
if(person == emptyPerson){
//NULL
}
问题在于NULL检查看起来很奇怪。您可以先询问它是否可用然后获取对象,但要求是这些操作必须是原子的。
第三个选项是返回指针:
Person* person = map.get("sample");
if(person == NULL){
//NULL
}
我不想这样做,因为它容易出错。用户需要删除我在内部创建的指针。
我正在考虑返回一个包装用户对象的类,如:
value_reference<std::map, Person> person = map.get("sample");
if(value_reference.hasValue() ){
Person p = value_reference;
}
那么你认为最好的方法是什么?
你知道任何与我的分布式地图的要求相似的api吗?
答案 0 :(得分:1)
我会说像选项3这样的东西是最好的。您可以使用C ++ 11中引入的标准智能指针类型之一来模拟它,因此您仍然可以创建指针,但用户不必释放它。如下所示:
std::unqiue_ptr<Person> person = map.get("sample");
if(person) {
person->makeMeASandwitch();
}
答案 1 :(得分:1)
根据您的术语“分布式地图”,我做出以下假设:
如果这是真的,那么迭代器不是你想要的,也不是你想要的STL容器模型。 C ++ Iterator概念要求您实现预增量(++i
)运算符,如果您的数据是无序的并且分布在多个节点上,那么请求“给我下一个条目”是没有意义的。
如果你想出于互操作性原因想要模拟STL容器和迭代器,你可能会创建一个可怕的kludge:让map end()
方法返回一个sentinel迭代器实例,并让你的迭代器operator++()
返回同样的哨兵。实际上,每个迭代器都会指向“地图中的最后一个元素”。我强烈建议不要采取这种方法,除非有必要,我认为不会。
听起来你想要的是一个简单的CRUD模型,必须明确请求更新。在这种情况下,您的API看起来像:
template <typename TKey, typename TValue>
class IMap<TKey, TValue>
{
public:
void create(TKey const & key, TValue const & value) = 0;
std::unique_ptr<TValue> retrieve(TKey const & key) = 0;
bool update(TKey const & key, TValue const & value) = 0;
bool remove(TKey const & key) = 0;
};
在检索案例中,您只需按照建议返回空指针。 std::unique_ptr<>
将确保调用者删除已分配的对象或明确取得对象的所有权。
“返回指向新分配对象的指针”的替代方法是让调用者传入引用,如果在地图中找到该值,该方法将返回true。例如,这将允许调用者直接将对象检索到数组槽或其他本地结构中,而无需中间堆分配。
bool retrieve(TKey const & key, TValue & value) = 0;
使用此方法看起来像:
Person person;
if (map.retrieve("sample", person)) {
std::cout << "Found person: " << person << std::endl;
} else {
std::cout << "Did not find person." << std::endl;
}
你也可以提供两个重载,默认情况下,返回指针的那个可以用另一个实现:
template <typename TKey, typename TValue>
std::unique_ptr<TValue> IMap<TKey, TValue>::retrieve(TKey const & key)
{
TValue v;
return std::unique_ptr<TValue>(retrieve(key, v) ? new TValue(v) : nullptr);
}