C++重载下标解除引用,其中允许nullptr

问题描述:

嗨,我是一名学生,为学习目的开发各种抽象数据类型。我想重载下标操作符来查找这些ADT中的键。我无法避免我的代码插入缺少的键的情况。C++重载下标解除引用,其中允许nullptr

当从这些ADT中读取nullptr的返回值时,它表示未找到密钥。我希望我的ADT仅在写入或插入时添加新的密钥。我的代码是如何处理以下不正确的:

const char *x = tree["key"]; 

这里,如果“钥匙”没有找到我希望避免增加这个键和返回nullptr来表示它的缺席。只能在以下情况下添加密钥:

tree["key"] = "x"; 

这是一个非常微妙的错误。下面的测试返回true,但仅仅是因为被测试的值是hash [“key”] .val(恰好为null)。

if (!x) printf("%s not found!\n", "key"); 

我相信这可以通过使用const来实现,并使用了以下签名。

char const *operator[](char *index) const; 

这个const超载从不被调用。有人可以解释为什么会出现这种情况,或者是一个表现正确的示例签名(或者将强制评估这个超载的示例)。这里是我的代码:

#include <stdio.h> 
#include <string.h> 

class lookup { 
    lookup *left; 
    lookup *right; 
    char *key; 
    char *val; 

public: 
    lookup(char *k) { 
     left = nullptr; 
     right = nullptr; 
     val = nullptr; 
     key = new char[strlen(k)+1]; 
     strcpy(key, k); 
    } 

    ~lookup() { 
     if (key) delete key; 
     if (val) delete val; 
    } 

    /* read/write access */ 
    /* if the key does not exist, then create it */ 
    char *&operator[](char *index) { 
     printf(" []= x\n"); 

     int x = strcmp(index, key); 
     if (x < 0) { 
      if (left == nullptr) left = new lookup(index); 
      return (*left)[index]; 
     } 
     if (x > 0) { 
      if (right == nullptr) right = new lookup(index); 
      return (*right)[index]; 
     } 
     return val; 
    } 

    /* read only access */ 
    /* if the key does not exist, then return nullptr (not found) */ 
    char const *operator[](char *index) const { 
     printf(" x = *[]\n"); 

     int x = strcmp(index, key); 
     if (x < 0) { 
      if (left == nullptr) return nullptr; 
      else return (*left)[index]; 
     } 
     if (x > 0) { 
      if (right == nullptr) return nullptr; 
      else return (*right)[index]; 
     } 
     return val; 
    } 
}; 

int main(void) { 
    lookup tree("root"); 

    /* this creates the key (which is not intended) */ 
    const char *x = tree["key"]; 
    if (!x) printf("%s not found!\n", "key"); 

    /* only now should the key be created */ 
    tree["key"] = "value"; 
    return 0; 
} 
+0

请注意,如果您使用'new []'分配内容,则必须使用'delete []'释放它。如果你使用std :: string而不是C风格的字符串,你的代码会更清晰和简单。 –

+0

'if(key)delete key;' - 错误形式的'delete'。它应该是'delete []'。避免这一点,只使用'std :: string'。 – PaulMcKenzie

+0

*这个const超载从不被调用* - 将'lookup'作为一个const引用传递给一个函数,并尝试调用该函数内的'lookup :: operator []'。编译别无选择,只能调用'const'版本。 – PaulMcKenzie

你想tree["key"]不同的行为在const char *x = tree["key"];tree["key"] = "x";。这是不可能的。子表达式在语句中的位置对该子表达式的行为没有影响。

如果您可以更改下标操作符的返回类型,您可能会实现与所查找内容类似的行为。如果你永远不会将缺失的值添加到树中,并返回一些对象的行为是在赋值时添加元素(如果缺少),那么可以使用上面的两个语句来表现你喜欢的行为。

这就是说,上述可能会很棘手的实施,并可能有警告。也许你不需要能够使用operator[]查找一个对象,而不会错过插入。与其试图使用重载,不如使用单独的函数来执行它,比如Paul建议的std::map