Изменение значения пользовательского класса в диапазоне, основанном на loop [duplicate]

По вопросу «что мне делать с этим» может быть много ответов.

Более «формальный» способ предотвращения таких ошибок при разработке применяя дизайн по контракту в вашем коде. Это означает, что при разработке вы должны установить инварианты класса и / или даже предпосылки для функции и .

Короче говоря, инварианты класса гарантируют, что в вашем классе будут некоторые ограничения, которые не будут нарушены при нормальном использовании (и, следовательно, класс будет not получить в несогласованном состоянии). Предпосылки означают, что данные, данные как входные данные для функции / метода, должны соответствовать установленным ограничениям и никогда не нарушать их, а постулаты означают, что вывод функции / метода должен соответствовать установленным ограничениям снова не нарушая их. Условия контракта никогда не должны нарушаться во время выполнения программы без ошибок, поэтому дизайн по контракту проверяется на практике в режиме отладки, а отключен в выпусках , чтобы максимизировать развитую производительность системы.

Таким образом, вы можете избежать случаев NullReferenceException, которые являются результатом нарушения установленных ограничений. Например, если вы используете свойство объекта X в классе, а затем попытаетесь вызвать один из его методов, а X имеет нулевое значение, то это приведет к NullReferenceException:

public X { get; set; }

public void InvokeX()
{
    X.DoSomething(); // if X value is null, you will get a NullReferenceException
}

Но если вы установите «свойство X никогда не должно иметь нулевого значения» в качестве предпосылки для метода, вы можете предотвратить описанный ранее сценарий:

//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant () 
{
    Contract.Invariant ( X != null );
    //...
}

По этой причине Код Контракт существует для приложений .NET.

В качестве альтернативы дизайн по контракту может быть применен с использованием утверждений .

ОБНОВЛЕНИЕ: Стоит отметить, что этот термин был придуман Бертраном Майером в связи с его дизайном языка программирования Эйфеля .

30
задан Frank 7 September 2011 в 21:55
поделиться

4 ответа

Поскольку val не участвует в сравнении, его можно было объявить mutable

struct Foo {
  Foo(int i, int j) : id(i), val(j) {}
  int id;
  mutable int val;
  bool operator<(const Foo& other) const {
    return id < other.id;
  }
};

. Это означает, что значение val может изменяться в логически const const, что означает что он не должен влиять на другие операторы сравнения и т. д.

Или вы можете просто удалить и вставить, что занимает O (1) дополнительное время (по сравнению с доступом и изменением), если вставка использует позицию непосредственно перед старый, как подсказка.

Что-то вроде:

bool alreadyThere = !p.second; // you forgot the !
if (alreadyThere)
{
    Set::iterator hint = p.first;
    hint++;
    s.erase(p.first);
    s.insert(hint, f);
}
43
ответ дан Cubbi 28 August 2018 в 21:36
поделиться

Не пытайтесь решить эту проблему, работая над константой элементов в файле set. Вместо этого, почему бы не использовать map, который уже выражает отношения ключевого значения, которые вы моделируете, и предоставляет простые способы обновления существующих элементов.

18
ответ дан Mark B 28 August 2018 в 21:36
поделиться

Сделать val mutable as:

mutable int val;

Теперь вы можете изменять / изменять / мутировать val, даже если foo const:

void f(const Foo & foo)
{
     foo.val = 10;  //ok
     foo.id  = 11;  //compilation error - id is not mutable.
}

By Кстати, из вашего кода вы, кажется, думаете, что если p.second истинно, то значение уже существует в наборе, и поэтому вы обновляете связанное значение. Думаю, вы ошибаетесь. На самом деле это наоборот. doc в cpluscplus говорит:

Пара :: второй элемент в паре имеет значение true, если новый элемент был вставлен или false, если элемент с тем же

, что является правильным, на мой взгляд.


Однако, если вы используете std::map, ваше решение будет простым:

void update(std::map<int,int> & m, std::pair<int,int> value) 
{
    m[value.first] += value.second;
}

Что делает этот код? m[value.first] создает новую запись, если ключ не существует на карте, а значением новой записи является значение по умолчанию int, которое равно нулю. Поэтому он добавляет value.second в zero. Или, если ключ существует, он просто добавляет к нему value.second. То есть приведенный выше код эквивалентен этому:

void update(std::map<int,int> & m, std::pair<int,int> value) 
{
    std::map<int,int>::iterator it = m.find(value);
    if ( it != m.end()) //found or not?
           it.second += value; //add if found
    else
    {
           m.insert(value); //insert if not found
    }
}

Но это слишком много, не так ли? Это не очень хорошо. Более ранний из них более лаконичен и очень эффективен.

5
ответ дан Nawaz 28 August 2018 в 21:36
поделиться

вы можете использовать MAP, который имеет очень быстрый доступ к вашему элементу, если у вас есть KEY. в этом случае я думаю, что использование MAP было бы лучшим способом достижения максимальной скорости. STD :: MAP

1
ответ дан sam 28 August 2018 в 21:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: