Я знаю, что этот вопрос обсуждался несколько раз, но я не смог найти пост, в котором объясняется, почему необходимо сделать копию в случае операции постинкрементного увеличения.
Цитирование из ответа stackoverflow:
int j = i++; // j will contain i, i will be incremented.
int j = ++i; // i will be incremented, and j will contain i+1.
Что прекрасно имеет смысл, когда рассматривается определение post / pre increment. Много раз при сравнении производительности до / после увеличения говорят, что после увеличения нужно сделать копию, увеличить ее и вернуть копию, в то время как предварительное увеличение просто увеличивает значение и не создает копию.
Хотя производительность сравнивалась в десятках постов, я действительно не мог найти объяснения, почему копия должна быть сделана в случае постинкремента. Почему он не возвращает старое значение, а затем увеличивает значение переменной на единицу (или как бы ни был перегружен оператор), вместо того, чтобы создавать новый объект и возвращать его.
Разница в том, someval++
что возвращает someval
до приращения и для этого нужно запомнить, что someval
это с копией. Как еще вы могли бы вернуть исходное значение при обновлении, если исходное значение где-то не было сохранено?
Рассмотрим операторы до увеличения и после увеличения как стандартные функции:
// ++i
int pre_increment(int &i) {
i = i + 1;
return i;
}
// i++
int post_increment(int &i) {
int original_i = i;
i = i + 1;
return original_i;
}
Это должно помочь вам понять, почему во втором случае (i ++) вы ДОЛЖНЫ выполнить копию значения перед выполнением приращения.
Мне трудно сказать, как компиляторы могут оптимизировать операторы перед приращением и после приращения, чтобы не обязательно делать копии примитивных типов.
Я могу показать, как должна быть сделана копия для пользовательских типов для операторов постинкремента.
Давайте посмотрим упрощенно std::vector::iterator
,
Допустим, итератор хранит индекс, в дополнение к другим вещам.
struct iterator
{
size_t index;
iterator operator++(int )
{
iterator copy = *this;
this->index++;
return copy;
}
};
В таком случае невозможно вернуть *this
сначала, а затем увеличивайте индекс. Создание копии, увеличение индекса this
, а затем возврат копии позволяет нам сохранить семантику этой операции.