C++ c++;重载允许null ptr的下标解引用

C++ c++;重载允许null ptr的下标解引用,c++,variable-assignment,subscript,nullptr,C++,Variable Assignment,Subscript,Nullptr,嗨,我是一名学生,为学习目的开发各种抽象数据类型。我正在尝试重载下标操作符以查找这些ADT中的键。我无法避免代码插入缺失键的情况 从这些ADT读取时,返回值为nullptr表示未找到密钥。我希望我的ADT仅在写入或插入时添加新键。我的代码处理以下内容的方式不正确: const char *x = tree["key"]; 在这里,如果找不到“key”,我希望避免添加此key,并返回nullptr以指示其不存在。仅在以下情况下才应添加密钥: tree["key"] = "x"; 这是一个非常微

嗨,我是一名学生,为学习目的开发各种抽象数据类型。我正在尝试重载下标操作符以查找这些ADT中的键。我无法避免代码插入缺失键的情况

从这些ADT读取时,返回值为nullptr表示未找到密钥。我希望我的ADT仅在写入或插入时添加新键。我的代码处理以下内容的方式不正确:

const char *x = tree["key"];
在这里,如果找不到“key”,我希望避免添加此key,并返回nullptr以指示其不存在。仅在以下情况下才应添加密钥:

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

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

char const *operator[](char *index) 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;
}
#包括
#包括
类查找{
查找*左;
查找*右;
字符*键;
char*val;
公众:
查找(字符*k){
左=空PTR;
右=空PTR;
val=nullptr;
key=newchar[strlen(k)+1];
strcpy(键,k);
}
~lookup(){
如果(键)删除键;
如果(val)删除val;
}
/*读/写访问*/
/*如果密钥不存在,则创建它*/
字符*&运算符[](字符*索引){
printf(“[]=x\n”);
int x=strcmp(索引,键);
if(x<0){
if(left==nullptr)left=新查找(索引);
返回(*左)[索引];
}
如果(x>0){
if(right==nullptr)right=新查找(索引);
返回(*右)[索引];
}
返回val;
}
/*只读访问*/
/*如果密钥不存在,则返回nullptr(未找到)*/
字符常量*运算符[](字符*索引)常量{
printf(“x=*[]\n”);
int x=strcmp(索引,键);
if(x<0){
if(left==nullptr)返回nullptr;
否则返回(*左)[索引];
}
如果(x>0){
if(right==nullptr)返回nullptr;
否则返回(*右)[索引];
}
返回val;
}
};
内部主(空){
查找树(“根”);
/*这将创建密钥(这不是预期的)*/
const char*x=树[“键”];
如果(!x)printf(“%s未找到!\n”,“key”);
/*现在才应该创建密钥*/
树[“键”]=“值”;
返回0;
}
您希望
树[“键”]
const char*x=tree[“键”]中表现不同
树[“key”]=“x”中的代码>多。这是不可能的。子表达式在语句中的位置对该子表达式的行为没有影响

如果您可以更改下标运算符的返回类型,那么您可能会实现类似于您正在寻找的行为。如果从不向树中添加缺少的值,并返回某个对象,该对象的行为是在赋值时添加元素(如果缺少),则可以使用上述两条语句来实现任意行为


这就是说,上述措施可能很难实施,而且可能存在一些警告。也许您不需要使用
操作符[]
来查找对象而不插入未命中。与其尝试使用重载,不如使用一个单独的函数来完成,如Paul建议的
std::map

请注意,如果使用
new[]
分配某个对象,则必须使用
delete[]
将其释放。如果您使用std::strings而不是C样式的字符串,那么您的代码将更加清晰和简单。
if(key)delete key--错误的
删除形式
。它应该是
delete[]
。避免这种情况,只需使用
std::string
。永远不会调用此常量重载。-将
lookup
作为常量引用传递给函数,并尝试在该函数内调用
lookup::operator[]
。编译程序别无选择,只能调用
const
版本。还要注意
std::map::operator[]
如果不存在,则插入一个值。这就是为什么如果您不希望这种行为,并且存在诸如
map::insert()
之类的函数,就不调用它。为什么不以类似的方式设计类呢?@PaulMcKenzie我看不出
std::map
在这里有什么关系。它没有被使用。
#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;
}