Reputation: 77
I'm working on building a range minimum query program in C++ but I'm having a hard time working with dynamically sized vectors that are used throughout the program. Right now I am using a size_t**
to make a 2d array of indexes to an array of elements, but it's not very nice to work with. I would much rather leverage existing c++ data structures like vectors, but I'm not sure how to make a member variable that is a pointer to a vector or some other data structure that can be manipulated in this way and access from anywhere in the class.
When I tried using a vector
I could populate it and manipulate it in PrecomputedRMQ()
, but when I tried to query in rmq()
the memory was inaccessible and I would segfault.
In essence, how do I replace this use of size_t**
with a vector<vector<size_t>>
, and more generally, how do I initialize and allocate pointers to member variables of builtin data structures?
In Header:
private:
size_t** table;
In my cpp: Here is how I'm constructing my table right now
PrecomputedRMQ::PrecomputedRMQ(const RMQEntry* elems, size_t numElems) {
numElems = numElems;
table = new size_t*[numElems];
for (size_t i = 0; i < numElems; i++) {
table[i] = new size_t[numElems];
}
for (size_t i = 0; i < numElems; i++) {
table[i][i] = i;
}
// then I go on to populate the table using DP
}
size_t PrecomputedRMQ::rmq(size_t low, size_t high) const {
return table[low][high];
}
Upvotes: 0
Views: 163
Reputation: 16129
You could try something like this
(only slightly tested)
#include <memory>
template<typename DataType>
class Board {
std::unique_ptr<DataType[]> board;
public:
const int rows = 8;
const int cols = 8;
Board(int row, int col, const DataType& filler = {}) :
rows(row),
cols(col),
board(std::make_unique<DataType[]>(row*col)) {
std::fill_n(board.get(), rows*cols, filler);
}
DataType *operator[](int row) { return board.get()+row*cols; }
const DataType *operator[](int row) const { return board.get()+row*cols; }
};
template<typename DataType, int crows = 8, int ccols = 8>
class FixBoard {
std::array<DataType, crows*ccols> board;
public:
const int rows = crows;
const int cols = ccols;
FixBoard(const DataType& filler = {}) {
board.fill(filler);
}
DataType *operator[](int row) { return board.data()+row*cols; }
const DataType *operator[](int row) const { return board.data()+row*cols; }
};
Board can be sized on creation from some input, FixBoard requires compile time knowledge of the size.
Usage example
#include <iostream>
constexpr char BlockChar { '\xB2' }; // 178
constexpr char EmptyChar { '.' };
constexpr char BlankChar { ' ' };
template <typename BoardType>
void Display(const BoardType& board) {
for (int i = 0; i < board.rows; ++i ) {
for (int j = 0; j < board.cols; ++j ) {
//std::cout << this->operator[](i)[j];
std::cout << board[i][j];
}
std::cout << '\n';
}
}
void Test() {
constexpr int sx = 6, sy = 10;
Board<char> board(sx, sy, BlankChar);
board[3][5] = BlockChar;
Display(board);
FixBoard<char, sx, sy> fixBoard(BlockChar);
fixBoard[3][5] = BlankChar;
Display(fixBoard);
}
Missing headers, more constexpr, const and test.
Upvotes: 0
Reputation: 409482
The key to replacing your current explicit memory handling with std::vector
, you don't need the allocation loop.
All you need is e.g.
table = std::vector<std::vector<size_t>>(numElems, std::vector<size_t>(numElems));
That will create a vector of vectors, with all sizes already set and all elements allocated and zero-initialized (which differs from your current code which leaves the majority of elements uninitialized!).
After this your initialization loop and the use in rmq
should work as is. Iff the indexes low
and high
are in range of course.
Upvotes: 3