I have been working on a matrix library project similar to the vector library and am currently stuck at iterators. I have been trying to implement a column iterator for quite some time without the use of other libraries (besides iostream and fstream) and my workaround was to have a **columnVector that contains the references of a specified column when colBegin(i) or colEnd(i) is called. The implementation works but I can't manage to make it work aesthetically without going in myMatrix.columnVector as I want it to be encapsulated, rather I want to call matrix::iterator it = myMatrix.colBegin(i) and to iterate with addition and subtraction but my iterator subclass has only a 1d pointer (for the row iterator, hope I can use it for the column iterator as well).
Do you have an idea how to make a column iterator for a dynamically allocated 2d array?
Example of code (trying to keep it as short as possible):
using ll = unsigned long long;
template <typename Type> class matrix
{
// Iterator
public:
class iterator
{
protected:
Type* pointer;
public:
iterator() : pointer(nullptr) {}
iterator(Type* ptr);
Type& operator * ();
...
};
private:
ll numberOfColumns, numberOfRows;
Type** data;
public: // temporary, wish for it to be private
Type** columnVector;
public:
matrix() : numberOfColumns(NULL), numberOfRows(NULL), data(nullptr), columnVector(nullptr) {}
matrix(const ll, const ll);
~matrix();
Type*& operator [] (const ll value);
Type** colBegin(const ll index);
Type** colEnd(const ll index);
...
};
// Thought the constructor might be important since it allocates memory for columnVector as well
template <typename Type> matrix<Type> ::matrix(const ll _numberOfColumns, const ll _numberOfRows)
{
// Copy _numberOfColumns and _numberOfRows into this
numberOfColumns = _numberOfColumns;
numberOfRows = _numberOfRows;
// Allocates memory for data matrix
other.data = (Type**) new Type * [numberOfColumns];
for (size_t i = 0; i < numberOfColumns; i++)
other.data[i] = (Type*) new Type[numberOfRows];
// Fills data matrix with 0
for (size_t i = 0; i < other.numberOfColumns; i++)
for (size_t j = 0; j < other.numberOfRows; j++)
other.data[i][j] = 0;
// Allocation of space for columnVector
columnVector = new Type * [numberOfRows];
}
template <typename Type> Type** matrix<Type> ::colBegin(const ll index)
{
for (size_t i = 0; i < numberOfRows; i++)
columnVector[i] = &data[i][index];
return columnVector;
}
template <typename Type> Type** matrix<Type> ::colEnd(const ll index)
{
for (size_t i = 0; i < numberOfRows; i++)
columnVector[i] = &data[i][index];
return (columnVector + numberOfRows);
}
You don't even need an iterator. Each column is represented with an array. To iterate this array you need to know its beginning and the address of the element after the last one. So the Type* can represent you the iterator:
template <typename Type> class matrix
{
public:
using column_iterator = Type*;
};
So the colBegin/colEnd methods should look like that:
template<typename Type>
matrix<Type>::column_iterator matrix<Type>::colBegin(const ll index) {
return data[index];
}
template<typename Type>
matrix<Type>::column_iterator matrix<Type>::colEnd(const ll index) {
return data[index] + numberOfRows;
}
If you find that the code above iterates throught the row (which is not the case, as your contructor clearly describes data[i] as a column), you may define a class that represents an iterator:
class row_iterator {
public:
row_iterator(Type** data,
size_t rowIndex,
size_t columnIndex)
: m_data(data), m_rowIndex(rowIndex), m_columnIndex(columnIndex) {
}
bool operator == (const row_iterator &other) const {
return other.data == m_data &&
other.m_rowIndex == m_rowIndex &&
other.m_columnIndex == m_columnIndex;
}
row_iterator& operator ++() {
++m_columnIndex;
return *this;
}
row_iterator& operator ++(int) {
row_iterator temp = *this;
++*this;
return temp;
}
Type& operator *() const {
return m_data[m_columnIndex][m_rowIndex];
}
// other operators
private:
Type** m_data;
size_t m_rowIndex;
size_t m_columnIndex;
};
To use this iterator with the container you need to define:
row_iterator rowBegin(size_t rowIndex) {
return row_iterator(data, rowIndex, 0);
}
row_iterator rowEnd(size_t rowIndex) {
return row_iterator(rowIndex, rowIndex, numberOfColumns);
}
Related
I am trying to code a template array class and overloading some operators. Part of my code is as follows:
template.h:
main.cpp:
C2679 binary '<': no operator found which takes a right-hand operand of type 'Array<int>' (or there is no acceptable conversion)
What is causing this error?
What is causing this error?
You are using
return this < a;
this is a pointer while a is a reference to an object. It's analgous to comparing an int* with an int.
int a = 10;
int b = 11;
int* p = &b;
if ( p < a ) { ... }
That is not right.
That function needs to be implemented differently. You need to compare each item of the arrays and return an appropriate value.
template<typename T>
bool Array<T>::operator<(const T& a)
{
int lowerLength = std::min(this->arrLength, a.arrLengh);
for ( int i = 0; i < lowerLength; ++i )
{
if ( this->myArray[i] != a.myArray[i] )
{
return (this->myArray[i] < a.myArray[i]);
}
}
// If we get here, return a value based on which array has more elements.
return (this->arrLength < a.arrLengh)
}
While at it, make the member function a const member function.
bool Array<T>::operator<(const T& a) const;
and change the implementation accordingly.
In findBigPos() (and your other functions in Driver.cpp, too), you should be passing arr by reference, not by pointer. When arr is a pointer, arr[index] is the same as *(arr + index) - it performs pointer arithmetic to dereference the pointer at a given offset, it does not index into your array at all. That is why the compiler thinks you are comparing Array<int> objects, and not calling your operator[].
Try this instead:
#include "wallet.h"
#include "currency.h"
#include "array.h"
#include <iostream>
#include <string>
using namespace std;
template<typename T>
void recurSelectionSort(Array<T>&, int size, int index);
template<typename T>
int findBigPos(Array<T>&, int size, int index);
int main() {
//code
}
template<typename T>
void recurSelectionSort(Array<T>& arr, int size, int index) // move the biggest element in arr to index
{
if (index == size) {
return;
}
else if (index < size) {
int bigPos = findBigPos(arr, size, index); //position of "biggest" element
T bigVal = arr[bigPos]; //the value of "biggest" element
T copy = arr[index]; //copy of wat ever is going to get copy
arr[index] = bigVal;
arr[bigPos] = copy;
recurSelectionSort(arr, size, index + 1);
cout << arr;
}
}
template<typename T>
int findBigPos(Array<T>& arr, int size, int index)
{
if (index == size - 1) {
return index;
}
else
{
int bigPos = findBigPos(arr, size, index + 1);
return arr[bigPos] < arr[index] ? index : bigPos;
}
}
That said, there are some issues with your Array class itself, too.
You are not implementing the Rule of 3/5/0. Your class is lacking a copy constructor and a copy assignment operator, and in C++11 and later a move constructor and a move assignment operator.
you don't have a const version of your operator[] for your operator<< to use, since it takes a reference to a const Array<T> as input.
your operator[] is not checking for index < 0. And it would be better to throw a std::out_of_range exception instead of an int. If it throws at all. Typically, an array's operator[] should not perform bounds checking at all. That is why containers like std::vector and std::string have a separate at() method for handling bounds checking.
your operator< is not implemented correctly at all. You can't compare a Array<T>* pointer to a const T& reference. You probably meant to dereference the this pointer before comparing it to a, but then that would lead to an endless recursive loop. What you should do instead is change const T& a to const Array<T> &a and then compare the contents of this to the contents of a.
Try this:
#ifndef ARRAY_HEADER
#define ARRAY_HEADER
#include <iostream>
#include <stdexcept>
#include <utility>
template<typename T>
class Array
{
private:
int arrLength;
T* myArray;
public:
Array(int length = 5);
Array(const Array &a);
Array(Array &&a);
virtual ~Array();
int getLength() const;
Array& operator=(Array a);
T& operator[](int index);
const T& operator[](int index) const;
bool operator<(const Array &a) const;
friend std::ostream& operator<<(std::ostream &output, const Array &arr)
{
int arrSize = arr.getLength();
for (int i = 0; i < arrSize; i++) {
output << arr[i] << " ";
}
return output;
}
};
template<typename T>
Array<T>::Array(int length)
{
myArray = new T[length];
arrLength = length;
}
template<typename T>
Array<T>::Array(const Array<T> &a)
{
myArray = new T[a.arrLength];
arrLength = a.arrLength;
for(int i = 0; i < arrLength; ++i)
myArray[i] = a.myArray[i];
}
template<typename T>
Array<T>::Array(Array<T> &&a)
{
arrLength = a.arrLength;
myArray = a.myArray;
a.myArray = nullptr;
a.arrLength = 0;
}
template<typename T>
Array<T>::~Array()
{
delete[] myArray;
}
template<typename T>
int Array<T>::getLength() const
{
return arrLength;
}
template<typename T>
Array<T>& Array<T>::operator=(Array<T> a)
{
using std::swap;
swap(myArray, a.myArray);
swap(arrLength, a.arrLength);
return *this;
}
template<typename T>
T& Array<T>::operator[](int index) {
if ((index < 0) || (index >= arrLength)) {
throw std::out_of_range("index is out of range");
}
return myArray[index];
}
template<typename T>
const T& Array<T>::operator[](int index) const {
if ((index < 0) || (index >= arrLength)) {
throw std::out_of_range("index is out of range");
}
return myArray[index];
}
template<typename T>
bool Array<T>::operator<(const Array<T> &a) const
{
if (arrLength < a.arrLength)
return true;
if (arrLength == a.arrLength)
{
for (int i = 0; i < arrLength; ++i)
{
if (myArray[i] != a.myArray[i])
return myArray[i] < a.myArray[i];
}
}
return false;
}
#endif
I am trying (struggling) writing a generic vector class using std::unique_ptr. In my constructor I get this exception thrown:
Exception thrown: write access violation.
std::unique_ptr<int [0],std::default_delete<int [0]> >::operator[](...) returned nullptr.
This is the associated function:
template <class T>
Vector<T>::Vector(int n, const T &value) {
capacity = (n > initial_capacity) ? n : initial_capacity;
size = n;
for (int i = 0; i < n; i++) {
data[i] = value;
}
}
I also get an error here in the main.cpp file:
assert(nullVector.getCapacity() == 100);
I believe this is because I did not set the capacity in the std::unique_ptr if that is even possible.
Here is part of my header file:
#ifndef Vector_h
#define Vector_h
template <class T>
class Vector {
private:
static constexpr int initial_capacity = 100;
// Instance variables
int capacity = 0;
int size = 0;
std::unique_ptr<T[]> data = nullptr;
void deepCopy(const Vector<T> &source) {
capacity = source.size + initial_capacity;
for (int i = 0; i < source.size; i++) {
data[i] = source.data[i];
}
size = source.size;
}
void expandCapacity() {
auto oldData = std::move(data);
capacity *= 2;
for (int i = 0; i < size; i++) {
data[i] = oldData[i];
}
}
public:
// Constructors
Vector() = default; // empty constructor
Vector(int n, const T &value); // constructor
Vector(Vector<T> const &vec); // copy constructor
Vector<T>& operator=(Vector<T> const &rhs); // assignment operator
// Rule of 5
Vector(Vector<T> &&move) noexcept; // move constructor
Vector& operator=(Vector<T> &&move) noexcept; // move assignment operator
~Vector(); // destructor
// Overload operators
T& operator[](int index);
T const& operator[](int index) const;
bool operator==(const Vector<T>&) const;
//Vector<T>& operator+=(const Vector<T> &other) {
// Vector<T> newValue(size + other.size);
// std::copy(this->data, this->data + this->size, newValue.data);
// std::copy(other.data, other.data + other.size, newValue.data + this->size);
// newValue.swap(*this);
//}
friend Vector<T>& operator+(Vector<T> &source1, Vector<T> &source2) {
int n = source1.getSize() + source2.getSize();
Vector<T> newSource(n,0);
for (int i = 0; i < source1.size; i++) {
newSource[i] = source1[i];
}
for (int i = 0; i < source2.size; i++) {
newSource[i + source1.getSize()] = source2[i];
}
return newSource;
}
friend std::ostream& operator<<(std::ostream &str, Vector<T> &data) {
data.display(str);
return str;
}
// Member functions
void swap(Vector<T> &other) noexcept;
void display(std::ostream &str) const;
int getSize() const { return size; }
int getCapacity() const { return capacity; }
bool empty() const { return size == 0; }
void clear() { size = 0; }
T get(int index) const;
void set(int index, const T &value);
void set(int index, T &&value);
void insert(int index, const T &value);
void insert(int index, T &&value);
void remove(int index);
void push_back(const T &value);
void pop_back();
};
template <class T>
Vector<T>::Vector(int n, const T &value) {
capacity = (n > initial_capacity) ? n : initial_capacity;
size = n;
for (int i = 0; i < n; i++) {
data[i] = value;
}
}
Here is part of the main.cpp file:
#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <cassert>
#include <ostream>
#include "Vector.h"
int main() {
///////////////////////////////////////////////////////////////////////
///////////////////////////// VECTOR //////////////////////////////////
///////////////////////////////////////////////////////////////////////
Vector<int> nullVector; // Declare an empty Vector
assert(nullVector.getSize() == 0); // Make sure its size is 0
assert(nullVector.empty()); // Make sure the vector is empty
assert(nullVector.getCapacity() == 100); // Make sure its capacity is greater than 0
}
There is no such thing as a "capacity" of a unique_ptr. All an std::unique_ptr does is it holds on to a dynamically allocated object. It does not allocate an object by itself. Use std::make_unique() or new to create an new object and assign to your unique_ptr to hold on to.
I don't see you allocating any memory anywhere in your code. Unless you do allocate memory for your vector somewhere in a piece of code you didn't show, your data will just point to nullptr and trying to dereference it will crash (or worse). At least your expandCapacity() method does not seem to allocate any memory…
You probably should have a look at some material to learn about unique_ptr and smart pointers in general. For example: How to declare std::unique_ptr and what is the use of it? or this.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I was giving a adventurer class containing a bunch of functions and member variables.
One of them is:
string*** items;
so first I thought it was a 3d array that I have to make but I was told that it suppose to be a pointer to a 2d array.
What I tried to do was make a temp array
string** temp;
Init that and fill it, I then point my items to temp
items = &temp;
This works till the function exits. Then we I try and call a index value inside items
cout<<*item[0][0];
there is nothing. When temp disappears so does the array.
This line also doenst work
(*items) = new string*[2];
I couldn't find anything online that helped me.
How can I initialize items or keep the array data that i made using temp.
For those asking for the code, this is what they gave me:
class Adventurer{
private:
string*** items;
string name;
double maxCarryWeight;
double currentCarryWeight;
int currentNumberOfItems;
int maxNumberOfItems;
double health;
static int numberOfAdventurers;
public:
Adventurer(); //default constructor
Adventurer(const Adventurer& a); //copy constructor
~Adventurer();
bool pickUpItem(string it, double weight);
bool dropItem(string it);
bool dropItem(int index);
void setName(string n);
string getName() const;
void setMaxCarryWeight(double w);
double getMaxCarryWeight() const;
void setCurrentCarryWeight(double w);
double getCurrentCarryWeight() const;
void setMaxNumberOfItems(int n);
int getMaxNumberOfItems() const;
void setCurrentNumberOfItems(int n);
int getCurrentNumberOfItems() const;
int getNumberOfAdventurers() const;
void setHealth(double h);
double getHealth() const;
string** getItem(int index) const;
Adventurer& operator = (const Adventurer& a);
};
And said that
string*** items;
is a pointer to a 2d array
It's not entirely clear what you are trying to achieve from your question but it seems your main issue is likely to do with returning the address of a local variable when attempting to allocate your 2D C-style std::string array. Below is a very basic example of how to avoid such an issue via returning the allocated 2D array and then taking the address of this returned value and storing it in your std::string*** items variable.
// allocate memory for a 2D C-style array of std::string's
std::string** allocate_2d_array(std::size_t rows, std::size_t cols) {
std::string** items_arr = new std::string*[rows];
for (std::size_t i = 0; i < rows; ++i)
items_arr[i] = new std::string[cols];
return items_arr;
}
// print each element of the 2D C-style array via a pointer to the array
void print_items(std::ostream& os, std::string*** items, std::size_t rows, std::size_t cols) {
for (std::size_t i = 0; i < rows; ++i) {
for (std::size_t j = 0; j < cols; ++j)
os << (*items)[i][j] << ' ';
os << '\n';
}
}
// destruct the 2D C-style array
void deallocate_2d_array(std::string** items_arr, std::size_t rows, std::size_t cols) {
for (std::size_t i = 0; i < rows; ++i)
delete[] items_arr[i];
delete[] items_arr;
}
int main(void) {
std::size_t rows = 3; // matrix rows
std::size_t cols = 3; // matrix columns
// allocate a 2D array of std::string's
std::string** items_arr = allocate_2d_array(items, 3, 3);
// set the pointer to a 2D std::string array to address of items_arr
std::string*** items = &items_arr;
int count = 0;
// fill items_arr with data via items pointer
for (std::size_t i = 0; i < rows; ++i) {
for (std::size_t j = 0; j < cols; ++j)
(*items)[i][j] = std::to_string(++count);
}
print_items(std::cout, items); // print matrix to terminal
deallocate_2d_array(items_arr, rows, cols); // deallocate items_arr
}
However, as mentioned in the comments, this is not in keeping with modern c++ and one would much rather use a std::vector<std::vector<std::string>> to store a matrix of std::string instances.
You mentioned that using std::vector is not an option but I suspect that your teacher probably didn't say anything about making your own barebones dynamic array with similar semantics to a std::vector so that is always one way around these silly restrictions. With that in mind, below is the framework for a very basic (and untested) class which mimics a std::vector (without using allocators) which would make your task much simpler.
template<typename Ty>
class dynamic_array {
public:
typedef Ty value_type;
typedef Ty& reference;
typedef const Ty& const_reference;
typedef Ty* pointer;
typedef const Ty* const_pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// CONSTRUCTION/ASSIGNMENT
dynamic_array()
: arr_capacity(0), arr_size(0) {}
dynamic_array(size_type count)
: arr_capacity(count), arr_size(count) { allocate(count); }
~dynamic_array() { destroy(); }
dynamic_array& operator=(dynamic_array _other) {
swap(*this, _other);
return *this;
}
// CAPACITY
bool empty() const noexcept { return arr_size; }
size_type size() const noexcept { return arr_size; }
size_type capacity() const noexcept { return arr_capacity; }
void reserve(size_type new_cap) { if (new_cap > arr_capacity) reallocate(new_cap); }
// ELEMENT ACCESS
reference operator[](size_type n) { return arr[n]; }
const_reference operator[](size_type n) const { return arr[n]; }
// MODIFIERS
void clear() {
for (size_type i = 0; i < arr_size; ++i)
(&arr[i])->~value_type();
arr_size = 0;
}
void push_back(const value_type& _val) {
if (arr_size == arr_capacity) // TODO: expand arr using reallocate
pointer val = new (arr + arr_size) value_type(_val);
++arr_size;
}
void pop_back() {
(&arr[arr_size-1])->~value_type();
--arr_size;
}
void swap(dynamic_array& _other) {
std::swap(arr, _other.arr);
std::swap(arr_capacity, _other.arr_capacity);
std::swap(arr_size, _other.arr_size);
}
static void swap(dynamic_array& lhs, dynamic_array& rhs) { lhs.swap(rhs); }
private:
value_type* arr;
size_type arr_capacity;
size_type arr_size;
void allocate(size_type n) { arr = new value_type[n]; }
void reallocate(size_type new_cap) {
value_type* tmp = new value_type[new_cap];
size_type tmp_rows = (new_cap > arr_capacity) ? arr_capacity : new_cap;
for (size_type i = 0; i < tmp_rows; ++i)
tmp[i] = std::move(arr[i]);
delete[] arr;
arr = tmp;
arr_capacity = new_cap;
}
void destroy { clear(); delete[] arr; }
};
Then instead of messing around with lots of raw pointers and the headaches they bring, you can just pass around your dynamic_array<dynamic_array<std::string>> class instance without needing to worry about memory management.
Note: The above dynamic_array class is untested and probably requires some tweaks, it is also not a great example of implementing a STL-style container (you'd need allocator and iterator support), it is just intended as a barebones std::vector mimicking container to get around the "no vector" task requirement.
I am having trouble building a class that makes sure the user does not access an element that is off the end of the array, by building a class that mimics the behavior of an array, but adds a check. That is, this class will create a sequence of elements of a given type, and allow access to these elements with the [] bracket operator, but it will check to make sure that the user does not try to do something with an element that doesn't exist.
Here is the instructions on building it.
I have no idea how to make an index operator for this case. Please help me. Thanks!
Here is my 3 files I have so far...
dvd.h
class dvdArray{
dvd *elt;
int size;
static int defaultSieze;
int getSize();
void display();
dvdArray(unsigned int sz);
dvdArray();
dvdArray(dvdArray &obj);
~dvdArray();
};
dvd.cpp
dvd::dvd(){
id =0;
int n=5;
title = new char [n];
director = new char [n];
title[0] = '\0';
director[0] = '\0';
}
dvd::~dvd(void)
{
}
dvdArray::dvdArray(unsigned int sz){
elt = new dvd[sz];
}
dvdArray::dvdArray(){
size = defaultSieze;
elt = new dvd[defaultSieze];
}
dvdArray::dvdArray(dvdArray &obj){
size = obj.size;
elt = new dvd[defaultSieze];
for (int i=0; i!='\0'; ++i) {
elt[i]=obj.elt[i];
}
}
dvdArray::~dvdArray(void)
{
}
The easiest / cleanest thing to do is to derive from std::vector (or std::array if it suits your purposes better), which is safe as long as you don't then delete the object using a std::vector*, and as long as the functions you want to do checked access accept the parameter as a checked_vector and not a std::vector*/&...
Example:
template <typename T>
class checked_vector : public std::vector<T>
{
public:
// ...forwarding constructors
using std::vector::vector;
T& operator[](size_t n) { return at(n); }
const T& operator[](size_t n) const { return at(n); }
};
Note: that won't protect you from invalid use of iterators, such as incrementing them too far or adding an illegal offset to them.
If - for whatever reason - you're determined to use your own implementation...
dvd& dvdArray::operator[](size_t n)
{
if (n >= size)
throw std::runtime_error("invalid array index");
return dvd[sz];
}
const dvd& dvdArray::operator[](size_t n) const
{
if (n >= size)
throw std::runtime_error("invalid array index");
return dvd[sz];
}
I would do something simple.. General purpose array, bounds checked...
Not sure why you would need that however... Vectors are a very good alternative to arrays.
template <typename T> class myArray{
size_t size;
T *arr;
void allocate(size_t s){
if(s<1) arr = NULL;
else arr = new T[s];
size = s;
}
public:
myArray(){ allocate(10); } //default constructor
myArray(size_t s){ allocate(s); }
~myArray(){ if(arr!=NULL) delete[] arr; arr=NULL; }
T& operator[] (size_t s) {
if(s>=size) throw Error(); //or do whatever
else return arr[s];
}
};
i`m working on my assignment for univ, and since some parts are not really good explained i got some problems there is my structure and my constructor for it, it has to be dynamical but i get the fallowing error. Some help is really appreciated thank you.
.h:
const int days=31;
const int exp=6;
struct Array{
int days;
int exp;
int **M;
};
.cpp:
void constr(Array &loc){
//Construct of 31*6 Matrix, were 31 nr. of days and 6 specific types:
//0-HouseKeeping, 1-Food, 2-Transport, 3-Clothing, 4-TelNet, 5-others
loc.days = days;
loc.exp = exp;
loc.M=malloc(loc.days*sizeof(int*));
for(int i=0; i<loc.days;i++ ){
loc.M[i] = malloc(loc.exp*sizeof(int));
for (int j = 0; j< loc.exp; j++){
loc.M[i][j] = 0;
}
}
}
error:
..\src\structs.cpp: In function 'void constr(Array&)':
..\src\structs.cpp:7:36: error: invalid conversion from 'void*' to 'int**' [-fpermissive]
..\src\structs.cpp:9:40: error: invalid conversion from 'void*' to 'int*' [-fpermissive]
Since you asked for C++ constructors in your comment... See the code below. I also replaced your two-dimensional C-style array with a C++ vector. I added code comments to the relevant lines:
Array.h:
#pragma once
#include <vector>
struct Array
{
// this is a c++ constructor declaration
Array(int daysParam, int expParam);
int days;
int exp;
// use a vector of vectors instead allocating with new or malloc
// it is easier to initialize and the compiler will clean it up for you
std::vector<std::vector<int> > M;
};
Array.cpp:
#include "Array.h"
// Array constructor definition with initializer list
// all data members are initialized here by invoking their constructor
Array::Array(int daysParam, int expParam)
: days(daysParam),
exp(expParam),
M(daysParam, std::vector<int>(expParam, 0))
{
}
Example for usage of Array (Program.cpp):
#include "Array.h"
int main()
{
// create a new Array, using the c++ constructor
Array myArray(31, 6);
// access elements in the 2-dimensional array
int singleValue = myArray.M[15][3];
return 0;
}
I strongly advise you to read a book about C++
Since this is C++:
loc.M = new int*[loc.days];
for(int i=0; i<loc.days;i++ ){
loc.M[i] = new int[loc.exp];
for (int j = 0; j< loc.exp; j++){
loc.M[i][j] = 0;
}
}
loc.M = (int**)malloc(loc.days*sizeof(int*));
loc.M[i] = (int*)malloc(loc.exp*sizeof(int));
Please, stop using std::vector > or, worse T tab[][] for representing a 2D array. You should use a 1D array to store data, a an index array to store row pointers. That way, your data remains contiguous, and you still can have a nice syntax.
template<typename T>
class Array2D
{
std::vector<T> m_data;
std::vector<T*> m_ptr;
size_t m_iWidth;
size_t m_iHeight;
void Link(void)
{
for (unsigned int j = 0; j < m_iHeight; ++j)
m_ptr[j] = &m_data[j * m_iWidth];
}
public:
Array2D(void)
{
};
Array2D(const size_t i_width, const size_t i_height) :
m_iWidth(i_width),
m_iHeight(i_height),
m_data(i_width * i_height),
m_ptr(i_height)
{
Link();
}
void Resize(const size_t niou_width, const size_t niou_height)
{
if (m_iWidth == niou_width && m_iHeight == niou_height)
return;
m_iWidth = niou_width;
m_iHeight = niou_height;
m_data.resize(niou_height * niou_width);
m_ptr.resize(niou_height);
Link();
}
typename std::vector<T>::iterator begin(void)
{
return m_data.begin();
}
typename std::vector<T>::iterator end(void)
{
return m_data.end();
}
void assign(T value)
{
m_data.assign(m_iWidth * m_iHeight, value);
}
Array2D(const Array2D& a) :
m_iWidth(a.m_iWidth),
m_iHeight(a.m_iHeight),
m_data(a.m_data)
{
m_ptr.resize(m_iHeight);
Link();
}
Array2D& operator=(const Array2D a)
{
swap(*this, a);
return *this;
}
template <typename U>
friend void swap(Array2D<U>& first, Array2D<U>& second)
{
using std::swap;
swap(first.m_iHeight, second.m_iHeight);
swap(first.m_iWidth, second.m_iWidth);
swap(first.m_data, second.m_data);
swap(first.m_ptr, second.m_ptr);
}
~Array2D()
{
};
T* operator[](const size_t ligne)
{
return m_ptr[ligne];
};
const T* operator[](const size_t ligne) const
{
return m_ptr[ligne];
};
T& operator()(const size_t col, const size_t lig)
{
return m_ptr[lig][col];
};
const T& operator()(const size_t col, const size_t lig) const
{
return m_ptr[lig][col];
};