Путаница с перегрузкой операторов и кучей против стека - PullRequest
0 голосов
/ 08 марта 2019

Я смотрю на следующий учебник: http://www.videotutorialsrock.com/opengl_tutorial/animation/home.php

У этого человека есть векторный класс:

class Vec3f {
private:
    float v[3];
public:
    Vec3f();
    Vec3f(float x, float y, float z);

    float &operator[](int index);
    float operator[](int index) const;

    Vec3f operator*(float scale) const;
    Vec3f operator/(float scale) const;
    Vec3f operator+(const Vec3f &other) const;
    Vec3f operator-(const Vec3f &other) const;
    Vec3f operator-() const;

    const Vec3f &operator*=(float scale);
    const Vec3f &operator/=(float scale);
    const Vec3f &operator+=(const Vec3f &other);
    const Vec3f &operator-=(const Vec3f &other);

    float magnitude() const;
    float magnitudeSquared() const;
    Vec3f normalize() const;
    float dot(const Vec3f &other) const;
    Vec3f cross(const Vec3f &other) const;
};

С примером определения:

Vec3f Vec3f::operator*(float scale) const {
    return Vec3f(v[0] * scale, v[1] * scale, v[2] * scale);
}

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

РЕДАКТИРОВАТЬ: я основываю свое понимание на этом: Как вернуть объект класса по ссылке в C ++?

Ответы [ 4 ]

4 голосов
/ 08 марта 2019
Vec3f Vec3f::operator*(float scale) const {
    return Vec3f(v[0] * scale, v[1] * scale, v[2] * scale);
}

При этом используется возвращаемое значение, поэтому возвращается значение экземпляра класса, созданного этой строкой, а не самого экземпляра.

Это принципиально не отличаетсяот return 1;.Возвращается значение one, а не какой-либо конкретный экземпляр или член класса, содержащий это значение.Как и во всем остальном, ответственность за реализацию состоит в том, чтобы выяснить, как выполнить то, о чем просит код - в этом случае, гарантируя, что существует некоторый экземпляр для хранения возвращаемого значения с соответствующим временем жизни.

1 голос
/ 08 марта 2019

Вы можете посмотреть в следующем примере:

Vec3f Vec3f::operator*(float scale) const {
    return Vec3f(v[0] * scale, v[1] * scale, v[2] * scale);
}

Vec3f a(1,2,3);
Vec3f b;
b = a * 2;

В общем случае произойдет следующее:

  1. Реализация перегрузки оператора создаст новый экземпляр Ve3f с новыми аргументами, представляющими умножение.

  2. процедура возврата вызовет конструктор копирования по умолчанию b с созданным объектом в аргументе. Конструктор копирования будет копировать поля из своего аргумента в экземпляр 'b'.

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

Vec3f(const Ver3f &src)...

Таким образом, в результате вы получите новые объекты со всеми полями, скопированными из поля, созданного в операторе возврата. Это возврат по значению, как определено в c ++ для объектов.

Результат будет другим, если вы вернете объект указателем или ссылкой. Это приведет к повреждению памяти.

0 голосов
/ 08 марта 2019

Итак, у каждого процессора свое соглашение о вызовах.Для получения более подробной информации смотрите this и this

По сути, возвращаемое значение или адрес возвращаемого значения копируются в регистр, например, R0 в ARM.и EAX в x86, чтобы вызывающая функция могла получить к ней доступ.

0 голосов
/ 08 марта 2019

Это оператор двоичного умножения, который возвращает копию данных в экземпляре Vec3f, умноженную на float scale, в значение r для использования остальной частью выражения.

Как что работ уже дан ответ в Что такое rvalues, lvalues, xvalues, glvalues ​​и prvalues?

Также см. https://en.cppreference.com/w/cpp/language/operator_arithmetic

...