3

我正在用 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 类似于要求我的分布式地图吗?

4

2 回答 2

1

我会说像选项3这样的东西是最好的。您可以使用 C++11 中引入的标准智能指针类型之一来模拟它,因此您仍然可以创建指针,但用户不必释放它。所以像:

std::unqiue_ptr<Person> person = map.get("sample");
if(person) {
      person->makeMeASandwitch();
}
于 2013-08-21T21:03:32.607 回答
1

根据您的术语“分布式地图”,我做出以下假设:

  • 数据的一个子集在本地可用,对于不是远程获取的数据集,将需要执行。
  • 对返回对象的写入不应自动保存在数据存储中。应改为发出明确的更新请求。

如果这是真的,那么迭代器不是您想要的,您也不需要 STL 容器模型。C++ 迭代器概念要求您实现预增量 ( ++i) 运算符,如果您的数据是无序的并且分布在多个节点上,那么“给我下一个条目”的请求是没有意义的。

如果您出于互操作性的原因想要模拟 STL 容器和迭代器,您可能会创建一个可怕的组合:让 map 的end()方法返回一个哨兵迭代器实例,并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);
}
于 2013-08-21T21:06:50.623 回答