Операторы приращения префикс/постфикс

Я хочу убедиться, что правильно понимаю pass-by-value vs pass-by-reference. В частности, я рассматриваю префикс/постфиксные версии оператора increment ++ для объекта.

Предположим, что мы имеем следующий класс X:

class X{
private:
    int i;
public:
 X(){i=0;}
 X& operator ++ (){ ++i; return *this; } //prefix increment

 X operator ++ (int unused){ //postfix increment
  X ret(*this);
  i++;
  return ret;
 }

 operator int(){ return i; } //int cast
};

Прежде всего, правильно ли я применил операторы приращения префикса/постфикса?

Во-вторых, насколько эффективно память является оператором постфикса, по сравнению с префиксом? В частности, сколько экземпляров объекта X создается при использовании каждой версии оператора?

Объяснение того, что происходит с возвратом по ссылке и возвратом по значению, может помочь мне понять.


Изменить: например, со следующим кодом...

X a;
X b=a++;

... есть а и b теперь псевдонимы?

Ответ 1

Это правильная реализация. Типично, что постфиксный оператор будет хуже по производительности, потому что вам нужно создать другую копию, прежде чем делать приращение (и именно поэтому я привык всегда использовать префикс, если мне не нужно что-то еще).

С возвратом по ссылке вы возвращаете ссылку l-value на текущий объект. Компилятор обычно реализует это, возвращая адрес текущего объекта. Это означает, что возвращение объекта так же просто, как возврат числа.

Однако с возвратом по значению копия должна быть выполнена. Это означает, что во время возврата (вместо адреса) будет копироваться дополнительная информация, а также конструктор копирования для вызова. Именно здесь происходит ваш успех.

Эффективность вашей реализации выглядит с точки зрения типичных реализаций.

EDIT: Что касается вашего добавления, нет, они не являются псевдонимами. Вы создали два отдельных объекта. Когда вы возвращаетесь по значению (и когда вы создали новый объект из оператора postfix increment), этот новый объект помещается в отдельную ячейку памяти.

Однако в следующем коде а и b являются псевдонимами:

 int a = 0;
 int& b = ++a;

b - адрес, который ссылается на.

Ответ 2

Более идиоматично вызывать приращение префикса самого объекта в приращении постфикса:

X operator++(int)
{
    X copy(*this);
    ++*this;         // call the prefix increment
    return copy;
}

Логика приращения объекта X, таким образом, содержится исключительно в префиксной версии.

Ответ 3

Ваши операторы реализованы правильно.

В префиксном операторе копии X не выполняются.

В операторе postfix одна копия создается для ret, и потенциально другая копия создается при возврате из функции, но все компиляторы будут удалять эту копию.