简体   繁体   中英

Question about Dynamic memory allocation in C++ for 3D array

I want to write a fuction to creat a 3D Matrix,but I have a broblem when I try to display it,Please help me,Thanks.

My teacher gave me his codes.His codes can create a 2D array which has Dynamic memory, I want to change his codes to creat a 3D matrix. When I tried to display the Matrix,I realize the array I created is a 2D array,And Because I just begin to use C++,I can't find my mistake.

/*<Array3D.h>*/
#pragma once
#ifndef _ARRAY_3D_H_
#define _ARRAY_3D_H_

//-----------------------------------------
#include <cassert>
#include <vector>
using namespace std;

template<typename T>
class Array3D
{
public:
    typedef Array3D<T> _Myt;
    Array3D()
        : m_nRows(0)
        , m_nCols(0)
        , m_nDepths(0)
    {}

    Array3D(size_t r, size_t c,size_t d)
    {
        Resize(r, c, d);
    }

    //Allocating memory size
    void Resize(size_t r, size_t c,size_t d)
    {
        if (r == m_nRows && c == m_nCols && d==m_nDepths) { return; }

        bool bValid = r > 0 && c > 0 && d>0;
        if (!bValid) return;

        m_nRows = r;
        m_nCols = c;
        m_nDepths = d;
        m_v.resize(m_nRows * m_nCols * m_nDepths);
    }

    const T* operator[](size_t r) const
    {
        assert(r >= 0 && r < m_nRows);
        return &(*(m_v.begin() + (r * m_nCols * m_nDepths)));
    }

    T* operator[](size_t r)
    {
        assert(r >= 0 && r < m_nRows);
        return &(*(m_v.begin() + (r * m_nCols * m_nDepths)));
    }

    //Gets the start position of a one-dimensional array
    const T* GetRawPointer() const { return &(m_v[0]); }
          T* GetRawPointer() { return &(m_v[0]); }

    long Rows() const
    {
        return static_cast<long>(m_nRows);
    }

    long Cols() const
    {
        return static_cast<long>(m_nCols);
    }

    long Depths() const
    {
        return static_cast<long>(m_nDepths);
    }

    long TotalSize() const
    {
        return static_cast<long>(m_nRows * m_nCols * m_nDepths);
    }

    void ClearUp()
    {
        m_nRows = 0;
        m_nCols = 0;
        m_nDepths = 0;
        m_v.clear();
    }

    bool IsEmpty() const { return m_v.empty(); }

protected:
    vector<T>   m_v;//  Internally a one-dimensional  is used
    size_t      m_nRows; 
    size_t      m_nCols; 
    size_t      m_nDepths; 
};

<Matrix3D.h>
#pragma once
#include "Array3D.h"
class Matrix3D
{
public:
    Matrix3D(int r = 0, int c = 0, int d = 0)
    {
        setSize(r, c, d);
    }

    void setSize(int r, int c, int d) { m_data3D.Resize(r, c, d); }
    void clear() { m_data3D.ClearUp(); }

    int rows() const { return m_data3D.Rows(); }
    int cols() const { return m_data3D.Cols(); }
    int Depths() const { return m_data3D.Depths(); }

    void display() const;

    //Operator Overloading
    float* operator[](int rIndex) { return m_data3D[rIndex]; }
    const float* operator[](int rIndex) const { return m_data3D[rIndex]; }

private:
    Array3D<float> m_data3D;
};
#include "Matrix3D.h"
#include <iostream>
using namespace std;


void Matrix3D::display() const
{
    if (m_data3D.IsEmpty())
    {
        cout << "empty matrix" << endl;
        return;
    }

    cout << "------------------------" << endl;
    const int rows = this->rows();
    const int cols = this->cols();
    const int Depths = this->Depths();
    cout << rows << "x" << cols << "x" << Depths << endl;
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        { 
            for(int k = 0 ;k < Depths; k++)
            {
                    cout << m_data3D[i][j][k] << ' '; /*This section will pose an error "E0142"*/
            }
            cout << endl;
         }
        
    }
}

I am going to guess that your teachers class was Array2D and that you mostly just added m_nDepths to it to turn it into Array3D . If this assumption is not right, then my answer here is most likely going to be completely wrong.

But if I am right, then his operator[] looked something like:

T* operator[](size_t r)
{
    assert(r >= 0 && r < m_nRows);
    return &(*(m_v.begin() + (r * m_nCols)));
}

Which means that when you then do m_data2D[i][j] , what happens is that the first [i] applies to the Array2D . This, as shown above, returns a pointer (in your case likely a float* ). The [j] is then applied to this pointer, which results in some pointer arithmetic that results in a float (for a float *x ; x[y] means *(x+y) ).

In other words, your teacher stores his 2D array line by line in a 1D array, and when you [] into it you get a pointer to the right line that you can then further [] into.

This is all fine.

The problem is when you add a third dimension to this and try the same approach: The first [] still returns a float* (but this time to the correct 2D matrix), the second [] returns a float (the first element in the correct line of the 2D matrix), and the third [] tries to apply to a float - which it cannot, and you get the error.

There are two ways to fix this:

  • Change the return type of Array3D::operator[] to return some kind of 2D array type whose operator[] works like the original Array2D .
  • Abandon the operator[] approach and replace it with a member function that takes 3 arguments and returns the correct element right away. I think this is what I would prefer myself.

For the second option, something like (not tested, rather large chance I messed up the order of the arguments):

T element(size_t x, size_t y, size_t z) const
{
    assert(x >= 0 && x < m_nDepths);
    assert(y >= 0 && y < m_nCols);
    assert(z >= 0 && z < m_nRows);
    return *(m_v.begin() + (x * m_nCols * m_nDepths +
                            y * m_nCols +
                            z));
}

T& element(size_t x, size_t y, size_t z)
{
    assert(x >= 0 && x < m_nDepths);
    assert(y >= 0 && y < m_nCols);
    assert(z >= 0 && z < m_nRows);
    return *(m_v.begin() + (x * m_nCols * m_nDepths +
                            y * m_nCols +
                            z));
}

Which turns cout << m_data3D[i][j][k] << ' '; into cout << m_data3D.element(i,j,k) << ' ';

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM