возвращая либо значение, либо значение - PullRequest
0 голосов
/ 23 февраля 2019

Я хочу определить s[i], чтобы вернуть 0, если s[0] никогда не был назначен, и вернуть ссылку на s[i], если s[i] был назначен ранее (для реализации разреженного массива).Следующий код делает это, но в конечном итоге создает s[i] всякий раз, когда я пытаюсь получить его значение, из-за семантики map.

struct svec{
  map<int,double> vals;
  /*                                                                                                
  double operator[](int index){                                                                     
    return (vals.count(index) > 0) ? vals[index] : 0                                                        ;                                                                           
    else return 0;                                                                                  
  }                                                                                                 
  */
  double &operator[](int index){
    return vals[index];
  }
};

int main(){
svec s;
s[0] = 10;
cout << s[1] << endl;
}

Я хочу, чтобы закомментированный код использовался для разрешения выраженияs[1].Но если я раскомментирую это, я получаю ошибку.

1 Ответ

0 голосов
/ 23 февраля 2019

Вы не можете перегружать возвращаемые значения, поэтому вам придется придерживаться либо возврата по ссылке, либо по значению (или по указателю и т. Д.).Проблема с возвратом по ссылке заключается в том, что вы должны ссылаться на существующее значение, которое находится в памяти.Это, конечно, хорошо, когда значение находится на карте.Если это не так, вы должны создать значение по умолчанию и сохранить его в памяти.Затем необходимо убедиться, что он правильно удален, чтобы не допустить утечки памяти, а также чтобы убедиться, что пользователь не хранит ссылки на значения, поскольку это может привести к непредвиденному поведению.

Кроме того, необходимо учитыватьтот факт, что пользователь может изменить значение, которое вы возвращаете.Если вы вернете то же значение по умолчанию, то пользователь сможет изменить его на другое значение.Тогда все последующие вызовы будут возвращать ссылку на новое значение.Сброс значения по умолчанию до 0 при каждом возврате также будет неожиданным для всех пользователей, которые все еще сохраняют ссылку на него.

Вероятно, вы могли бы решить эту проблему стабильным образом, но, вероятно, потребовалось бы много шаблонногокод.В этом случае я бы предложил обременять пользователя.

class SparseVector {
private:
    std::unordered_map<int, double> elements;

public:
    void set(int index, double value) {
        elements[index] = value;
    }

    double& get(int index, double& optional) {
        auto it = elements.find(index);
        if (it != elements.end())
            return it->second;
        else
            return optional;
    }

    double& get(int index) {
        auto it = elements.find(index);
        if (it != elements.end())
            return it->second;
        throw std::runtime_error(
            "Couldn't find element at index " + std::to_string(index) + 
            "! Use get(int index, double& optional) if you don't want errors."
        );
    }
}

int main() {
    double default_value = 0.0;
    SparseVector vector;

    std::cout << vector.get(0, default_value) << std::endl;
}
...