jeudi 1 juillet 2021

Why is my overloaded subscript operator for rvalue not called

I have looked up and down stack overflow and keep finding the same examples which I think I have implemented. I am trying to implement an associative array. I know there is std::map but I'd like to do the implementation myself for better control and better understanding.

I have overloaded the subscript operator for lvalue and rvalue. However in my code only the method for the lvalue is called and I can't find where I am mistaken. Can anyone point me in the right direction, please? Here's my code for the class. For now, it's not supposed to be efficient, just working would make me happy:

template<typename K, typename V>
class AssocArray {

private:
    size_t _arraySize = 0;
    K *_keyArray = nullptr;
    V *_valueArray = nullptr;

    void expandValueArray() {
        auto newValueArray = new V[_arraySize];
        // copy old values
        for (size_t i = 0; i < _arraySize - 1; ++i)
            newValueArray[i] = _valueArray[i];
        if (_valueArray)
            delete[] _valueArray;
        _valueArray = newValueArray;
    }

    void appendToKeyArray(K key) {
        auto newKeyArray = new K[_arraySize];
        // copy old keys
        for (size_t i = 0; i < _arraySize - 1; ++i)
            newKeyArray[i] = _keyArray[i];
        newKeyArray[_arraySize - 1] = key;
        delete[] _keyArray;
        _keyArray = newKeyArray;
    }

    bool keyExists(K key) {
        for (size_t i = 0; i < _arraySize; ++i)
            if (_keyArray[i] == key)
                return true;
        return false;
    }

    size_t getExistingKeyIndex(K key) {
        for (size_t i = 0; i < _arraySize; ++i)
            if (_keyArray[i] == key)
                return i;
    }

public:
    ~AssocArray() {
        delete[] _valueArray;
        delete[] _keyArray;
    }

    V operator[](K key) const {
        if (keyExists(key))
            return _valueArray[getExistingKeyIndex(key)];
        else
            throw std::out_of_range("Key does not exist");
    }

    V &operator[](K key) {
        if (keyExists(key))
            return _valueArray[getExistingKeyIndex(key)];

        // key does not exist
        ++_arraySize;
        appendToKeyArray(key);
        expandValueArray();
        return _valueArray[_arraySize - 1];
    }

    void print() {
        std::cout << "Content of AssocArray:" << std::endl;
        if (!_arraySize) std::cout << "none" << std::endl;
        for (int i = 0; i < _arraySize; ++i) {
            std::cout << "[" << _keyArray[i] << "] => " << _valueArray[i] << std::endl;
        }
    }
};

and here is how I call it and produce the undesired behavior:

#include <iostream>
#include "AssocArray.h"

int main() {
       AssocArray<std::string, std::string> assocArray;

        (assocArray)["Toni"] = "seven";
        (assocArray)["Sam"] = "five";
        std::cout << "assocArray before lookup of non existing key:" << std::endl << std::endl;
        assocArray.print();
        // FixMe: appends key to assocArray, but shouldn't
        std::cout << std::endl << "lookup of non existing key:" << std::endl;
        auto key = "Megan";
        std::cout << "[" << key << "] => " << assocArray[key] << std::endl << std::endl;

        std::cout << "assocArray after lookup of non existing key:" << std::endl;
        assocArray.print();
}

The output is this (see that Megan is added to the array where it shouldn't be):

assocArray before lookup of non existing key:

Content of AssocArray:
[Toni] => seven
[Sam] => five

lookup of non existing key:
[Megan] => 

assocArray after lookup of non existing key:
Content of AssocArray:
[Toni] => seven
[Sam] => five
[Megan] => 

Why don't I get an exception? Why is the overloaded method for the lvalue called here? Thanks for looking into this.

Aucun commentaire:

Enregistrer un commentaire