【问题标题】:Am I misunderstanding how pointers work?我是否误解了指针的工作原理?
【发布时间】:2016-09-30 04:07:30
【问题描述】:

我有一个类 Matrix 和另一个类 Camera,我想在其中使用 Matrix。我的 Matrix 类如下所示:

class Matrix4f {
    public:
        Matrix4f() {
            this->setMatrix(EMPTY);
        }

        Matrix4f(Matrix4f &m2) {
            this->setMatrix(m2.matrix);
        }

        static Matrix4f& Matrix4f::identity() {
           Matrix4f& identity = Matrix4f() ;
           identity.setMatrix(IDENTITY);
           return identity;
        }

        void setMatrix(float f[4][4]) {
            for (int r = 0; r < 4; r++) {
                 for (int c = 0; c < 4; c++) {
                      this->matrix[r][c] = f[r][c];
                 }
            }
        }

        Matrix4f& operator=(const Matrix4f &m2) {
             this->setMatrix(m2.matrix);
        }
    private:
        float matrix[4][4];
        static float EMPTY[4][4] = {
             { 0, 0, 0, 0 },
             { 0, 0, 0, 0 },
             { 0, 0, 0, 0 },
             { 0, 0, 0, 0 }
        }; // initialize an empty array (all zeros);
        static float IDENTIY[4][4] = {
             { 1, 0, 0, 0 },
             { 0, 1, 0, 0 },
             { 0, 0, 1, 0 },
             { 0, 0, 0, 1 }
        }; // initialize a identity (array)
}

我的相机课上有这个:

class Camera {
    public:
        Camera() {
            this->calculateProjection();
        }

        Matrix4f* getProjection() {
            return this->projection;
        }
    private:
        Matrix4f* projection;

        Matrix4f* calculateProjection() {
             this->projection = &Matrix4f::identity();
             // modify this->projection...

             return this->projection;
        }
  }

当我尝试创建一个 Camera 实例然后获取它的投影时,我得到的东西看起来像是一个损坏的对象(矩阵完全填充为大的负数)。

我真的很困惑是什么原因造成的我的代码会像这样行为不端。
我相当肯定它处理的是编译器自动删除的引用,我认为它处理的是单位矩阵,但它并没有真正的意义。

不应该将单位矩阵复制到投影矩阵中,这样单位矩阵是否被垃圾收集也没有关系?

我发现我实际上可以通过以下任一方式使这段代码工作 使单位矩阵创建一个新的 Matrix4f() 并返回该值或使 getProjection() 返回 calculateProjection()。
问题是,我真的不想做任何一个。
我不希望 Identity 构造一个新的 Matrix4f,因为我必须处理破坏它,而且我不想要 getProjection( ) 来调用 calculateProjection() 因为该方法很昂贵,
实际上应该只调用一次,因为投影矩阵永远不会改变。

【问题讨论】:

  • identity 是什么?
  • 你为什么要在相机中使用指针?
  • 你的班级名称是什么MatrixMatrix4f
  • 关于身份:这是第一个错误的事情。没有参考。而且你需要一个更好的拷贝构造函数(const)。
  • 摆脱指针(返回对象),摆脱重载的复制构造函数和赋值运算符,神奇地你会看到你的代码工作。

标签: c++ class pointers reference


【解决方案1】:

你的

 Matrix4f& Matrix4f::identity() {
           Matrix4f& identity = Matrix4f() ;
           identity.setMatrix(IDENTITY);
           return identity;
        }

返回对本地对象的引用。一旦 identity() 退出,对象就消失了。

你需要在堆上分配它然后返回它。

或者在你的相机类中声明一个矩阵

  ...
  private:
    Matrix4f projection;

    Matrix4f& calculateProjection() { 
         ... modify ...
         return this->projection;
    }
   ...

【讨论】:

  • 看,我不明白的是,如果我在 calculateProjection() 方法中放置一个断点,Visual Studio 会显示投影矩阵已完全初始化为所有正确的值。 .. 另外,如果 getProjection() 只是返回 calculateProjection() 那么代码会神奇地工作,这没有意义,因为单位矩阵不应该死吗?
  • @ThomasPaine 你处于未定义的行为领域,它有时有效,有时无效
  • Matrix4f&amp; identity = Matrix4f() ; 在符合标准的编译器中会出错。 OP 可能会受到 MSVC 的阻碍
  • 返回对静态对象的引用将是另一种解决方案(这里可能更好,因为它的意图似乎是始终返回相同的矩阵)
  • 如何在 Matrix4f 类中正确创建一个静态对象,该对象将被初始化为我希望它返回的单位矩阵?
【解决方案2】:

我是否误解了指针的工作原理?

也许吧。您的代码有几个我可以看到的问题:

    Matrix4f& Matrix4f::identity() {
       Matrix4f& identity = Matrix4f() ;
       identity.setMatrix(IDENTITY);
       return identity;
    }

这会创建一个临时对象和一个对它的引用(该引用称为identity)。我不确定临时对象是否在Matrix4f&amp; identity = Matrix4f() ; 之后被销毁,或者在函数返回时被销毁 - 但无论哪种方式,临时对象在函数返回之前被销毁,因此函数返回对已被销毁对象的引用。

this->projection = &Matrix4f::identity();

this-&gt;projection 然后设置为被销毁的临时对象的地址。

稍后,您尝试访问已被销毁的临时对象,不出所料地得到垃圾数据。

另外,identity(函数)不是静态的,因此您不能将其称为Matrix4f::identity()

【讨论】:

  • 但是编译器不应该将 identity() 返回的矩阵中的数据复制到投影矩阵中吗?那么,如果 identity() 矩阵被破坏,如果数据已经被复制到投影中,为什么还要重要呢?
  • 返回对局部变量的引用是未定义的行为。干净利落。不要这样做。
  • @ThomasPaine identity 在分配给this-&gt;projection 之前被销毁。 (这是一个指针赋值,所以它不会复制任何矩阵数据)
  • @ThomasPaine 什么投影矩阵?我在您的代码中没有看到投影矩阵。我看到一个名为projection 的指针,但指向矩阵的指针不是矩阵。 (就像一张写着房子地址的纸不是房子)
  • 我可能听起来像是破纪录,但为什么 Visual Studio 的调试器会显示投影已完美初始化?如果我在 calculateProjection() 方法中添加一个断点,就在 return 语句之前,它显示投影矩阵实例已完全初始化为我希望它初始化的内容(已修改的单位矩阵)。就像投影实例在方法结束后立即重置一样。
猜你喜欢
  • 2014-01-27
  • 1970-01-01
  • 2015-12-02
  • 1970-01-01
  • 1970-01-01
  • 2016-02-20
  • 2012-12-11
  • 2011-02-18
  • 2018-02-17
相关资源
最近更新 更多