简体   繁体   中英

Problems with implementing 2D array template in C++

I tried to create a template for a generic 2D array, which would allow me to create arrays of different data types and fill them with random values. My current code seemingly creates three objects, but fills them with the same random values, and the double type massive does not even have double values. I think the problem is somewhere in the constructor and with the pointers, but I am not sure how to fix this.

My class:

template <typename T>
    class MATRIX
    {
    private:
      T** M;
      int m = 8;
      int n = 12;
    public:
    MATRIX(T matr[8][12]);
      void fill();
      };

Constructor:

template <typename T>
 MATRIX<T>::MATRIX(T matr[8][12]){
    M = (T**) new T*[m];
    for (int i = 0; i < m; i++)
      M[i] = (T*)new T[n];
}

Method:

    template <typename T>
    void MATRIX<T>::fill(){
        T randomNumber;
        srand((unsigned) time(0));
        for (int i = 0; i < m; i++){
          for (int j = 0; j < n; j++){
            randomNumber = (rand() % (122 + 1 - 65)) + 65;
            M[i][j] = randomNumber;} } }

Main:

 int main() {
    int intMatr[8][12];
    MATRIX<int>a(intMatr);
    a.fill();
    
    double doubleMatr[8][12];
    MATRIX<double>b(doubleMatr);
    b.fill();
    
    char charMatr[8][12];
    MATRIX<char>c(charMatr);
    c.fill();
    return 0; }

Not really a direct answer to your question, howeverr try not to use new/delete if you don't have to as is shown in this example (note the array2d_t class is something I wrote earlier and reused for this example so it can do a bit more then needed) I also show how to use c++'s random generators to create characters for your matrix.

#pragma once

#include <vector>
#include <iostream>
#include <random>
#include <utility>
#include <string>
#include <stdexcept>

//---------------------------------------------------------------------------------------------------------------------

template<typename type_t, std::size_t rows_v, std::size_t cols_v>
struct array2d_t 
{
    constexpr array2d_t() :
        m_values{}
    {
    }

    constexpr explicit array2d_t(const type_t(&values)[rows_v][cols_v])
    {
        // constexpr compatible initialization
        for (auto row = 0; row < rows_v; ++row)
        {
            for (auto col = 0; col < cols_v; ++col)
            {
                m_values[row][col] = values[row][col];
            }
        }
    }

    ~array2d_t() = default;

    // return a row
    constexpr auto operator[](const std::size_t row)
    {
        //assert(row < rows_v);
        if (row >= rows_v) throw std::invalid_argument("row out of bounds");
        return row_t(&m_values[row][0]);
    }

    // return a const row
    constexpr auto operator[](const std::size_t row) const
    {
        //assert(row < rows_v);
        if (row >= rows_v) throw std::invalid_argument("row out of bounds");
        return const_row_t(&m_values[row][0]);
    }

    // return iterator to the first row (so array can be used in range based for loop)
    constexpr auto begin() 
    {
        return std::begin(m_values);
    }

    // return iterator to the last row (so array can be used in range based for loop)
    constexpr auto end() 
    {
        return std::end(m_values);
    }

    constexpr std::size_t rows() const 
    {
        return rows_v;
    }

    constexpr std::size_t columns() const
    {
        return cols_v;
    }

private:
    //-----------------------------------------------------------------------------------------------------------------
    ///  row helper
    struct row_t
    {
        constexpr row_t(type_t* row) :
            m_row{ row }
        {
        }

        constexpr type_t& operator[](const std::size_t column) const
        {
            //assert(column < cols_v);
            if (column >= cols_v) throw std::invalid_argument("column out of bounds");
            return m_row[column];
        }

        constexpr auto begin() const
        {
            return std::begin(m_row);
        }

        constexpr auto end() const
        {
            return begin() + rows_v;
        }

    private:
        type_t* m_row;
    };

    //-----------------------------------------------------------------------------------------------------------------
    // row helper for const 
    struct const_row_t
    {
        constexpr const_row_t(const type_t* row) :
            m_row{ row }
        {
        }

        constexpr const type_t& operator[](const std::size_t column) const
        {
            //assert(column < cols_v);
            if (column >= cols_v) throw std::invalid_argument("column out of bounds");
            return m_row[column];
        }

        constexpr auto begin() const
        {
            return std::begin(m_row);
        }

        constexpr auto end() const
        {
            return begin() + rows_v;
        }

    private:
        const type_t* m_row;
    };

    type_t m_values[rows_v][cols_v];
};

template<typename type_t, std::size_t rows_v, std::size_t cols_v>
std::ostream& operator<<(std::ostream& os, array2d_t<type_t,rows_v,cols_v>& arr)
{
    for (const auto& row : arr)
    {
        bool comma = false;

        for (const auto& value : row)
        {
            if (comma) std::cout << ", ";
            std::cout << value;
            comma = true;
        }

        std::cout << "\n";
    }

    std::cout << "\n";

    return os;
}

//---------------------------------------------------------------------------------------------------------------------

class MATRIX :
    public array2d_t<char, 8, 12>
{
public:

    void fill()
    {
        // initialize a vector of valid character for random to pick from
        // static ensures this is only done on first call to function
        static std::vector<char> valid_chars = []
        {
            std::vector<char> chars;
            chars.reserve(52);
            for (char c = 'A'; c < 'Z'; ++c) chars.push_back(c);
            for (char c = 'a'; c < 'z'; ++c) chars.push_back(c);
            return chars;
        }();

        // this is how to setup random number generation in C++
        static std::random_device rd{};
        static std::default_random_engine random{ rd() };
        static std::uniform_int_distribution<std::size_t> distribution(0, valid_chars.size() - 1);

        for (auto& row : *this)
        {
            for (auto& value : row)
            {
                value = valid_chars[distribution(random)];
            }
        }
    }
};

//---------------------------------------------------------------------------------------------------------------------

int main()
{
    MATRIX m;
    m.fill();

    std::cout << m;
    return 0;
}

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