运算符重载和堆与堆栈的混淆

Confusion on operator overloading and heap vs stack

我正在查看以下教程: http://www.videotutorialsrock.com/opengl_tutorial/animation/home.php

这个人有向量class:

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);
}

我不明白为什么会这样。这不应该立即导致分段错误吗? return 值在堆栈上,应该在所有这些函数终止时被删除。为什么它有效?我对堆栈与堆的理解不正确吗?

编辑:我的理解基于此: How to return a class object by reference in C++?

这是二元乘法运算符,它返回 Vec3f 实例中的数据副本,乘以 float scale 为右值,供表达式的其余部分使用。

的工作原理已在 What are rvalues, lvalues, xvalues, glvalues, and prvalues?

中得到解答

另见 https://en.cppreference.com/w/cpp/language/operator_arithmetic

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

这按值使用 return,所以 returned 是该行创建的 class 实例的 value,不是实例本身。

这与return 1;没有本质区别。 value 是 returned,而不是包含该值的任何特定实例或 class 成员。与几乎所有其他事情一样,实现的责任是弄清楚如何完成代码所要求的——在这种情况下,确保存在某个实例以在适当的生命周期内保存 returned 值。

所以,每个 cpu 都有自己的调用约定。有关更多详细信息,请查看 this and this

基本上,return 值,或 return 值的地址被复制到一个寄存器,如 ARM 中的 R0 和 x86 中的 EAX,以便函数的调用者可以访问它。

你可以看下面的例子:

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. return 过程将调用 b 的默认复制构造函数,并在参数中构造对象。复制构造函数会将字段从其参数复制到 'b' 的实例。

除了默认提供的浅拷贝之外,您始终可以实现自己的拷贝构造函数来执行其他操作。

Vec3f(const Ver3f &src)...

因此,您将获得一个新对象,其中的所有字段都是从 return 语句中创建的对象复制而来的。这是在 c++ 中为对象定义的 return 按值。

如果您 return 通过指针或引用编辑对象,结果会有所不同。它会导致内存损坏。