【问题标题】:C++ Avoiding Triple PointersC++ 避免三指针
【发布时间】:2019-02-28 02:58:33
【问题描述】:

我正在尝试创建一个 X 指针数组,引用维度为 Y 乘以 16 的矩阵。在 C++ 中是否有任何方法可以在不使用三重指针的情况下完成此操作?

编辑:为问题添加一些上下文。

屏幕上有许多几何图形,每个几何图形都有一个已展平为 1x16 数组的变换。每个快照代表每个数量的组件的转换。所以矩阵维度是 16 x num_components x num_snapshots ,其中后两个维度在运行时是已知的。最后,我们有许多应用了运动的几何图形。

我正在创建一个接受三重指针参数的函数,尽管在我的情况下我不能使用三重指针。我可以通过哪些其他方式传递这些数据(可能通过多个参数)?最坏的情况是,我考虑将整个 3D 矩阵展平为一个数组,尽管这似乎是一件草率的事情。有更好的建议吗?

我现在拥有的:

function(..., double ***snapshot_transforms, ...)

我想要完成的事情:

function (..., <1+ non-triple pointer parameters>, ...)

下面不是我创建的使用三元指针的函数,而是显示数据的全部内容。

static double ***snapshot_transforms_function (int num_snapshots, int num_geometries)
{
    double component_transform[16];

    double ***snapshot_transforms = new double**[num_snapshots];

    for (int i = 0; i < num_snapshots; i++)
    {
        snapshot_transforms[i] = new double*[num_geometries];

        for (int j = 0; j < num_geometries; j++)
        {
            snapshot_transforms[i][j] = new double[16];

            // 4x4 transform put into a 1x16 array with dummy values for each component for each snapshot
            for (int k = 0; k < 16; k++)
                snapshot_transforms[i][j][k] = k;
        }
    }

    return snapshot_transforms;
}

Edit2: 我不能创建新类,也不能使用像 std 这样的 C++ 特性,因为头文件中暴露的函数原型被放入一个包装器中(不知道如何解释三重指针)以翻译成其他语言。

Edit3: 在大家对 cme​​ts 的意见之后,我认为使用扁平数组可能是最好的解决方案。我希望有某种方法可以拆分这个三重指针,并使用包括单指针在内的简单数据类型将这些复杂的数据整齐地组织到多个数据片段中。尽管鉴于我在这里的警告,我认为没有一种很好的方法可以做到这一点。感谢大家的帮助=)

【问题讨论】:

  • 是的。这很容易!
  • "有没有办法" - 是的。怎么样,你问?这是你没有问的另一个问题。如果你能展示你不喜欢的代码也会有所帮助,并且有人会向你展示更好的处理方法。
  • @Yakk-AdamNevraumont 哈!已接受答案。
  • @RemyLebeau 我添加了一些代码来展示我想要完成的工作的要点。
  • @Ash 这看起来是正确的做法。

标签: c++ pointers matrix


【解决方案1】:

使用std::vector 更容易、更好且更不容易出错。毕竟,您使用的是 C++ 而不是 C。我用vectors 替换了所有C 风格的数组指针。 typedef doublecube 使您不必一遍又一遍地键入vector&lt;vector&lt;vector&lt;double&gt;&gt;&gt;。除了代码基本上和你的一样。

如果您实际上不需要虚拟值,我会完全删除最里面的 k 循环。 reserve 会为您保留真实数据所需的内存空间。

#include <vector>

using std::vector; // so we can just call it "vector"
typedef vector<vector<vector<double>>> doublecube;

static doublecube snapshot_transforms_function (int num_snapshots, int num_geometries)
{    
    // I deleted component_transform. It was never used

    doublecube snapshot_transforms;
    snapshot_transforms.reserve(num_snapshots);

    for (int i = 0; i < num_snapshots; i++)
    {
        snapshot_transforms.at(i).reserve(num_geometries);

        for (int j = 0; j < num_geometries; j++)
        {
            snapshot_transforms.at(i).at(j).reserve(16);

            // 4x4 transform put into a 1x16 array with dummy values for each component for each snapshot
            for (int k = 0; k < 16; k++)
                snapshot_transforms.at(i).at(j).at(k) = k;
        }
    }

    return snapshot_transforms;
}

【讨论】:

  • 不要像这样嵌套向量,你的数据局部性会非常糟糕。而是将矩阵展平为一维 (vector&lt;double&gt;) 并提供从 3D 坐标转换为平面索引的助手。
  • @Dustin 感谢您的建议,尽管我必须同意 Ben 的观点,而且我宁愿展平 3D 矩阵而不是嵌套向量。我没有在我的 OP 中提到,但我不能在这里使用 C++ 的许多特性,比如 std 库,因为我正在处理的这部分内容将被放入包装器并转换为其他语言。
【解决方案2】:

添加一点面向对象通常会使代码更易于管理——例如,这里有一些代码创建了一个包含 100 个 Matrix 对象的数组,每个矩阵的行数不同。 (如果您愿意,您也可以更改每个 Matrix 中的列数,但我将它们保留在 16):

#include <vector>
#include <memory>  // for shared_ptr (not strictly necessary, but used in main() to avoid unnecessarily copying of Matrix objects)

/** Represents a (numRows x numCols) 2D matrix of doubles */
class Matrix
{
public:
   // constructor
   Matrix(int numRows = 0, int numCols = 0)
      : _numRows(numRows)
      , _numCols(numCols)
   {
      _values.resize(_numRows*_numCols);
      std::fill(_values.begin(), _values.end(), 0.0f);
   }

   // copy constructor
   Matrix(const Matrix & rhs)
      : _numRows(rhs._numRows)
      , _numCols(rhs._numCols)
   {
      _values.resize(_numRows*_numCols);
      std::fill(_values.begin(), _values.end(), 0.0f);
   }

   /** Returns the value at (row/col) */
   double get(int row, int col) const {return _values[(row*_numCols)+col];}

   /** Sets the value at (row/col) to the specified value */
   double set(int row, int col, double val) {return _values[(row*_numCols)+col] = val;}

   /** Assignment operator */
   Matrix & operator = (const Matrix & rhs)
   {
      _numRows = rhs._numRows;
      _numCols = rhs._numCols;
      _values  = rhs._values;
      return *this;
   }

private:
   int _numRows;
   int _numCols;
   std::vector<double> _values;
};

int main(int, char **)
{
   const int numCols = 16;
   std::vector< std::shared_ptr<Matrix> > matrixList;
   for (int i=0; i<100; i++) matrixList.push_back(std::make_shared<Matrix>(i, numCols));

   return 0;
}

【讨论】:

  • 你的例子与OO无关。
  • @n.m.听起来您不太了解 O.O 的范围,并认为它适用于比实际范围更窄的设计。
  • 听起来你不太了解 O.O 的范围,并认为它适用于比实际更广泛的设计范围。创建一个类不是面向对象的。 STL 不是面向对象的。问亚历克斯·斯捷潘诺夫。
  • “封装是 OOP(面向对象编程)的基础之一。它是指将数据与操作该数据的方法捆绑在一起。” en.wikipedia.org/wiki/Encapsulation_(computer_programming)
  • “对我而言,OOP 仅意味着消息传递、本地保留、保护和隐藏状态进程,以及所有事物的极端后期绑定”(Alan Kay,术语)。
猜你喜欢
  • 2017-02-18
  • 2021-04-25
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
  • 2011-10-30
  • 1970-01-01
  • 2017-10-31
  • 1970-01-01
相关资源
最近更新 更多