i've got a Class Image with a member called buffer, a vector of unsigned char that store the pixels of image. I'd like to handle this buffer as a matrix.i'd like to access to the buffer as img[ i ][ j ] but i've not idea how? anyone can suggest me a solution?
here's my tentative:
unsigned char * &Image::operator[](int i) {
return buffer[ rows+i ]
}
i read this post then i think that is possible. my class is like that:
class Image {
private:
unsigned char * buffer;
int buf_size;
int rows;
int cols;
Phisical_img_manager phisical_img_manager;
const char * in_img_filename;
public:
unsigned char * & operator[](int i);
Image(const char * in_img_filename);
unsigned char * get_buffer();
int get_cols();
int get_rows();
};
Solution
You could do it in row-major order as below:
class Image {
int rows, cols;
unsigned char *buffer;
public:
// ...
unsigned char* operator[](int const i) { return &(buffer[i * cols]); }
unsigned char const* operator[](int const i) const { return &(buffer[i * cols]); }
};
Live Demo
Discussion
Your buffer is a contiguous block of memory. Of size N = rows * cols.
However the notion of an image is a set of pixels arranged in a 2D construct/matrix:
What we want is to arrange this 2D construct in the 1D buffer in computer's memory. We can do this in two ways:
Row major order.
Column major order.
In row major order we store each row of the image one after the other. That is, for the following size 2x2 image
the respective buffer storage would look like:
In column major order we store each column of the image one after the other. That is, the buffer storage for the same size 2x2 image would look like:
Programming languages that support multi-dimensional arrays either implement row-major or column-major storage order for them. In C and C++ row-major order is used.
In the code showed above we implement row-major order. We define an overloaded subscript operator that takes as input the row index (e.g., i) we want to access. Multiplying this i with the number of columns we get the starting index of the ith row in the image. We return the address of the element that lies in this specific address. This address marks the beginning of a sub-array of the original buffer as well as the beginning of the ith row. To clarify further see the following code example:
Image I(2, 3);
I[1][2] = 42;
calling I[1][2] = 42 is like calling:
(I.operator[](1))[2];
sub-call I.operator[](1) returns a pointer to the address where the second row of the image starts. Then we use this returned pointer as an ordinary dynamic allocated array. In this specific example we add 2 to this pointer (i.e., that is what [2] does) and thus we get the element of the row that lies 2 positions after the first element of the row (i.e., the third element of the second row of the image).
Alternative Solution For C++11
If your compiler supports C++11 and smart pointers you could do the following scheme in order to avoid memory management. Furthermore I would overload operator()(std::size_t const, std::size_t const) because overloading as above you expose the buffer and thus you're hurting encapsulation:
class Image {
int rows, cols;
std::unique_ptr<unsigned char[]> buffer;
public:
Image(int const rows_ = 0, int const cols_ = 0)
: rows(rows_), cols(cols_), buffer(new unsigned char[rows * cols]) {}
Image(Image const &other)
: rows(other.rows), cols(other.cols), buffer(new unsigned char[rows * cols]) {
std::copy(other.buffer.get(), other.buffer.get() + (rows * cols), buffer.get());
}
Image(Image &&other)
: rows(other.rows), cols(other.cols), buffer(std::move(other.buffer)) {
other.rows = 0;
other.cols = 0;
}
unsigned char& operator()(std::size_t const i, std::size_t const j) {
return buffer[cols * i + j];
}
unsigned char const& operator()(std::size_t const i, std::size_t const j) const {
return buffer[cols * i + j];
}
Image& operator=(Image const &other) {
rows = other.rows;
cols = other.cols;
buffer.reset(new unsigned char[rows * cols]);
std::copy(other.buffer.get(), other.buffer.get() + (rows * cols), buffer.get());
return *this;
}
Image& operator=(Image &&other) {
rows = other.rows;
cols = other.cols;
buffer.swap(other.buffer);
other.rows = 0;
other.cols = 0;
return *this;
}
// ...
};
Live Demo
Related
Is there a way to implement an operator like [][] for a 1D array?
I want to change the implementation of a 2D vector to a 1D vector in my code (cause this increases the execution speed by about %50 in my program). 2D vector supports [y][x]. How can I have such functionality for a 1D vector?
I can do it like this:
const size_t Y_Axis { 20 };
const size_t X_Axis { 30 };
std::vector<char> vec( Y_Axis * X_Axis );
size_t row { 5 };
size_t col { 28 };
vec[ row * X_Axis + col ] = 't'; // assign a value to a specific row-column
However, typing this formula multiple times throughout a source file seems like violating DRY (don't repeat yourself). How can I do this in an efficient and idiomatic way? I want to hide the complexity and make things a bit abstracted just like operator[][] of 2D vector does.
C++ does not allow virtual containers. So the operator [] is expected to return a true object of the expected size, if you want all the goodies like true iterators to work smoothly.
Here is a post of mine about the iterator question for multi-dimensional containers and a more general question on Code Review
If you only want to build an operator[](int) that returns something that can accept a second [], it can easily be done for a 2D vector, by returning a plain pointer inside the internal data array of a vector:
template <typename T>
class vec2d {
std::vector<T> data;
size_t _cols;
public:
vec2d(int rows, int cols, T* src = nullptr)
: data(rows * cols), _cols(cols) {
if (src != nullptr) {
for (T& val : data) {
val = *src++;
}
}
}
T* operator [] (size_t row) {
return data.data() + row * _cols;
}
const T* operator [] (size_t row) const {
return data.data() + row * _cols;
}
size_t rows() const {
return data.size() / _cols;
}
size_t cols() const {
return _cols;
}
};
And here is an example usage:
int main() {
vec2d<char> v(3, 4, "ABCDEFGHIJKL");
for (size_t i = 0; i < v.rows(); i++) {
for (size_t j = 0; j < v.cols(); j++) {
std::cout << v[i][j] << ' ';
}
std::cout << "\n";
}
}
I am trying to implement Strassen's algorithm for matrix multiplication in C++, and I want to find a way to split two matrices into four parts each in constant time. Here is the current way I am doing so:
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
A11[i][j] = a[i][j];
A12[i][j] = a[i][j+n];
A21[i][j] = a[i+n][j];
A22[i][j] = a[i+n][j+n];
B11[i][j] = b[i][j];
B12[i][j] = b[i][j+n];
B21[i][j] = b[i+n][j];
B22[i][j] = b[i+n][j+n];
}
}
This approach is obviously O(n^2), and it adds n^2*log(n) to the runtime, as it is called for each recursive call.
It seems that the way to do this in constant time is to create pointers to the four sub-matrices, rather than copy over the values, but I am having a difficult time figuring out how to create those pointers. Any help would be appreciated.
Don't think of matrices, think of matrix views.
A matrix view has pointer to a buffer of T, a width, a height, an offset, and a stride between columns (or rows).
We can start with an array view type.
template<class T>
struct array_view {
T* b = 0; T* e = 0;
T* begin() const{ return b; }
T* end() const{ return e; }
array_view( T* s, T* f ):b(s), e(f) {}
array_view( T* s, std::size_t l ):array_view(s, s+l) {}
std::size_t size() const { return end()-begin(); }
T& operator[]( std::size_t n ) const { return *(begin()+n); }
array_view slice( std::size_t start, std::size_t length ) const {
start = (std::min)(start, size());
length = (std::min)(size()-start, length);
return {b+start, length};
}
};
Now our matrix view:
temlpate<class T>
struct matrix_view {
std::size_t height, width;
std::size_t offset, stride;
array_view<T> buffer;
// TODO: Ctors
// one from a matrix that has offset and stirde set to 0.
// another that lets you create a sub-matrix
array_view<T> operator[]( std::size_t n ) const {
return buffer.slice( offset+stride*n, width ); // or width, depending on if row or column major
}
};
Now your code does work on matrix_views, not matrices.
You could create a submatrix class that holds the location in the parent matrix of the smaller matrix you want to use. Mostly just what you already have for your Matrix, except you'd need to store starting indexes for the row and columns, then offset your indexing by those offsets. If done right the main/root matrix would be a submatrix with the full matrix as the bounds.
I looked into two different method to allocate memory for the elements of a matrix
Method n.1
int** matrix = new int*[rows];
for (int i = 0; i < rows; ++i)
matrix[i] = new int[cols];
Method n.2
int** matrix = new int*[rows];
if (rows)
{
matrix[0] = new int[rows * cols];
for (int i = 1; i < rows; ++i)
matrix[i] = matrix[0] + i * cols;
}
I can figure out what Method n.1 does, but I can't figure out what exactly is supposed to do the if clause in Method n.2 (I would implement it without and it doesn't work, with the if clause, it does...)
EDIT: Here is a code showing my problem. Why does it take so long to load (~30seconds)?
http://codepad.org/uKvI8Tk3
Codepad refuses to show the output (timeout) so if you want to run it, just compile it on your own.
Also, why cout << statements are not executed once the program starts?
Method n.3: write your own Matrix class, internally using a single std::vector<int> and being clever about access by (row,col) indices.
struct Matrix
{
explicit Matrix(unsigned int rows, unsigned int cols) : data_(rows*cols), cols_(cols) {}
const int& operator()(unsigned int row, unsigned int col) const
{
return data_[row*cols_ + col];
}
private:
std::vector<int> data_;
unsigned int cols_;
};
Edit: iff the memory overhead of a vector is an issue in the last example, you can consider using a single dynamically allocated array of length rows*cols, and make sure to call delete [] on it in the destructor.
Method n.2 is allocating a unique block to contain the sequence of all rows. Hence the first row is a pointer to the whole block. If rows==0 you have not space to hold the pointer to the (empty) space, so you cannot make the allocation.
I would steer toward method 4 suggested in the other answer:
class Matrix {
Matrix(int rows, int cols): rows_(rows), cols_(cols) {
data_ = new int[rows*cols];
}
~Matrix() {
delete[] data_;
}
int &operator()(int i,int j) {return data_[cols_*i+j];}
int operator()(int i,int j) const {return data_[cols_*i+j];}
private:
int rows_,cols_;
int *data_;
};
As in the subject how create new 2D array in C++?
This code below does not work quite well.
int** t = new *int[3];
for(int i = 0; i < 3; i++)
t[i] = new int[5];
You have a * in the wrong spot. Try:
int **t = new int *[3];
Would vector< vector< int > > work?
You may want to "flatten" the 2D matrix into a 1D array, storing its elements in a convenient container like std::vector (this is more efficient than having a vector<vector<T>>). Then you can map the 2D (row, column) matrix index into the 1D array index.
If you store the elements in the matrix row-wise, you can use a formula like this:
1D array index = column + row * columns count
You can wrap that in a convenient C++ class (overloading operator() for proper matrix element access):
template <typename T>
class Matrix {
public:
Matrix(size_t rows, size_t columns)
: m_data(rows * columns), m_rows(rows), m_columns(columns) {}
size_t Rows() const { return m_rows; }
size_t Columns() const { return m_columns; }
const T & operator()(size_t row, size_t column) const {
return m_data[VectorIndex(row, column)];
}
T & operator()(size_t row, size_t column) {
return m_data[VectorIndex(row, column)];
}
private:
vector<T> m_data;
size_t m_rows;
size_t m_columns;
size_t VectorIndex(size_t row, size_t column) const {
if (row >= m_rows)
throw out_of_range("Matrix<T> - Row index out of bound.");
if (column >= m_columns)
throw out_of_range("Matrix<T> - Column index out of bound.");
return column + row*m_columns;
}
};
How do you dynamically allocate a 2D matrix in C++?
I have tried based on what I already know:
#include <iostream>
int main(){
int rows;
int cols;
int * arr;
arr = new int[rows][cols];
}
It works for one parameter, but now for two. What should I do?
A matrix is actually can be represented as an array of arrays.
int rows = ..., cols = ...;
int** matrix = new int*[rows];
for (int i = 0; i < rows; ++i)
matrix[i] = new int[cols];
Of course, to delete the matrix, you should do the following:
for (int i = 0; i < rows; ++i)
delete [] matrix[i];
delete [] matrix;
I have just figured out another possibility:
int rows = ..., cols = ...;
int** matrix = new int*[rows];
if (rows)
{
matrix[0] = new int[rows * cols];
for (int i = 1; i < rows; ++i)
matrix[i] = matrix[0] + i * cols;
}
Freeing this array is easier:
if (rows) delete [] matrix[0];
delete [] matrix;
This solution has the advantage of allocating a single big block of memory for all the elements, instead of several little chunks. The first solution I posted is a better example of the arrays of arrays concept, though.
You can also use std::vectors for achieving this:
using: 'std::vector< std::vector >'
Example:
#include <vector>
std::vector< std::vector<int> > a;
//m * n is the size of the matrix
int m = 2, n = 4;
//Grow rows by m
a.resize(m);
for(int i = 0 ; i < m ; ++i)
{
//Grow Columns by n
a[i].resize(n);
}
//Now you have matrix m*n with default values
//you can use the Matrix, now
a[1][0]=1;
a[1][1]=2;
a[1][2]=3;
a[1][3]=4;
//OR
for(i = 0 ; i < m ; ++i)
{
for(int j = 0 ; j < n ; ++j)
{ //modify matrix
int x = a[i][j];
}
}
Try boost::multi_array
#include <boost/multi_array.hpp>
int main(){
int rows;
int cols;
boost::multi_array<int, 2> arr(boost::extents[rows][cols] ;
}
arr = new int[cols*rows];
If you either don't mind syntax
arr[row * cols + col] = Aij;
or use operator[] overaloading somewhere. This may be more cache-friendly than array of arrays, or may be not, more probably you shouldn't care about it. I just want to point out that a) array of arrays is not only solution, b) some operations are more easier to implement if matrix located in one block of memory. E.g.
for(int i=0;i < rows*cols;++i)
matrix[i]=someOtherMatrix[i];
one line shorter than
for(int r=0;i < rows;++r)
for(int c=0;i < cols;++s)
matrix[r][c]=someOtherMatrix[r][c];
though adding rows to such matrix is more painful
const int nRows = 20;
const int nCols = 10;
int (*name)[nCols] = new int[nRows][nCols];
std::memset(name, 0, sizeof(int) * nRows * nCols); //row major contiguous memory
name[0][0] = 1; //first element
name[nRows-1][nCols-1] = 1; //last element
delete[] name;
#include <iostream>
int main(){
int rows=4;
int cols=4;
int **arr;
arr = new int*[rows];
for(int i=0;i<rows;i++){
arr[i]=new int[cols];
}
// statements
for(int i=0;i<rows;i++){
delete []arr[i];
}
delete []arr;
return 0;
}
or you can just allocate a 1D array but reference elements in a 2D fashion:
to address row 2, column 3 (top left corner is row 0, column 0):
arr[2 * MATRIX_WIDTH + 3]
where MATRIX_WIDTH is the number of elements in a row.
Here is the most clear & intuitive way i know to allocate a dynamic 2d array in C++. Templated in this example covers all cases.
template<typename T> T** matrixAllocate(int rows, int cols, T **M)
{
M = new T*[rows];
for (int i = 0; i < rows; i++){
M[i] = new T[cols];
}
return M;
}
...
int main()
{
...
int** M1 = matrixAllocate<int>(rows, cols, M1);
double** M2 = matrixAllocate(rows, cols, M2);
...
}
The other answer describing arrays of arrays are correct.
BUT if you are planning of doing a anything mathematical with the arrays - or need something special like sparse matrices you should look at one of the many maths libs like TNT before re-inventing too many wheels
I have this grid class that can be used as a simple matrix if you don't need any mathematical operators.
/**
* Represents a grid of values.
* Indices are zero-based.
*/
template<class T>
class GenericGrid
{
public:
GenericGrid(size_t numRows, size_t numColumns);
GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue);
const T & get(size_t row, size_t col) const;
T & get(size_t row, size_t col);
void set(size_t row, size_t col, const T & inT);
size_t numRows() const;
size_t numColumns() const;
private:
size_t mNumRows;
size_t mNumColumns;
std::vector<T> mData;
};
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns);
}
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns, inInitialValue);
}
template<class T>
const T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx) const
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx)
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
void GenericGrid<T>::set(size_t rowIdx, size_t colIdx, const T & inT)
{
mData[rowIdx*mNumColumns + colIdx] = inT;
}
template<class T>
size_t GenericGrid<T>::numRows() const
{
return mNumRows;
}
template<class T>
size_t GenericGrid<T>::numColumns() const
{
return mNumColumns;
}
Using the double-pointer is by far the best compromise between execution speed/optimisation and legibility. Using a single array to store matrix' contents is actually what a double-pointer does.
I have successfully used the following templated creator function (yes, I know I use old C-style pointer referencing, but it does make code more clear on the calling side with regards to changing parameters - something I like about pointers which is not possible with references. You will see what I mean):
///
/// Matrix Allocator Utility
/// #param pppArray Pointer to the double-pointer where the matrix should be allocated.
/// #param iRows Number of rows.
/// #param iColumns Number of columns.
/// #return Successful allocation returns true, else false.
template <typename T>
bool NewMatrix(T*** pppArray,
size_t iRows,
size_t iColumns)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{ // I prefer using the shorter 0 in stead of NULL.
if (!((*pppArray) != 0)) // Test if the first element is currently unassigned.
{ // The "double-not" evaluates a little quicker in general.
// Allocate and assign pointer array.
(*pppArray) = new T* [iRows];
if ((*pppArray) != 0) // Test if pointer-array allocation was successful.
{
// Allocate and assign common data storage array.
(*pppArray)[0] = new T [iRows * iColumns];
if ((*pppArray)[0] != 0) // Test if data array allocation was successful.
{
// Using pointer arithmetic requires the least overhead. There is no
// expensive repeated multiplication involved and very little additional
// memory is used for temporary variables.
T** l_ppRow = (*pppArray);
T* l_pRowFirstElement = l_ppRow[0];
for (size_t l_iRow = 1; l_iRow < iRows; l_iRow++)
{
l_ppRow++;
l_pRowFirstElement += iColumns;
l_ppRow[0] = l_pRowFirstElement;
}
l_bResult = true;
}
}
}
}
}
To de-allocate the memory created using the abovementioned utility, one simply has to de-allocate in reverse.
///
/// Matrix De-Allocator Utility
/// #param pppArray Pointer to the double-pointer where the matrix should be de-allocated.
/// #return Successful de-allocation returns true, else false.
template <typename T>
bool DeleteMatrix(T*** pppArray)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{
if ((*pppArray) != 0) // Test if pointer array was assigned.
{
if ((*pppArray)[0] != 0) // Test if data array was assigned.
{
// De-allocate common storage array.
delete [] (*pppArray)[0];
}
}
// De-allocate pointer array.
delete [] (*pppArray);
(*pppArray) = 0;
l_bResult = true;
}
}
}
To use these abovementioned template functions is then very easy (e.g.):
.
.
.
double l_ppMatrix = 0;
NewMatrix(&l_ppMatrix, 3, 3); // Create a 3 x 3 Matrix and store it in l_ppMatrix.
.
.
.
DeleteMatrix(&l_ppMatrix);