Generic vector class using smart pointers in C++ - c++

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.

Related

Pointer to **column_array of 2d dynamic array

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);
}

free(): double free detected in tcache 2

I'm writing my own dynamic array class in C++ (similarly to std::vector), and I'm running into a problem when having a dynamic array containing dynamic arrays.
Basically when having an array of all data types (int, double, float, std::string etc.) there is no problem and all the functionalities of the class works great.
When the data type is another array though something messes up and there is an error raising in the end of the program (free(): double free detected in tcache 2)
All of the code:
DynamicArray.h:
#pragma once
#include <iostream>
namespace Utils
{
template <typename T>
class DynamicArray
{
private:
size_t array_length;
T* array;
public:
~DynamicArray();
DynamicArray();
DynamicArray(const int& initialLength);
void Print();
size_t GetLength() const;
void AddItem(const T& newItem);
// TODO: void AddItems(const T* newItemsArray);
void RemoveItem(int index);
T& GetItem(int index);
void SetItem(const int& index, const T& newValue);
T& operator [](int index) const;
void ResetArray(T resetValue);
};
}
#include "DynamicArray.cpp"
DynamicArray.cpp:
#include "DynamicArray.h"
template<typename T>
Utils::DynamicArray<T>::~DynamicArray()
{
std::cout << "before del" << this->array_length << "\n";
if (this->array_length > 0)
delete[] this->array;
std::cout << "after del\n";
}
template<typename T>
Utils::DynamicArray<T>::DynamicArray()
{
this->array_length = 0;
}
template<typename T>
Utils::DynamicArray<T>::DynamicArray(const int& initialLength)
{
this->array_length = initialLength;
T* new_array = new T[initialLength];
this->array = new_array;
}
template<typename T>
void Utils::DynamicArray<T>::Print()
{
for (size_t i = 0; i < this->array_length; i++)
std::cout << this->array[i] << std::endl;
}
template<typename T>
size_t Utils::DynamicArray<T>::GetLength() const
{
return this->array_length;
}
template<typename T>
void Utils::DynamicArray<T>::AddItem(const T& newItem)
{
T* new_array = new T[this->array_length + 1];
for (size_t i = 0; i < this->array_length; i++)
new_array[i] = this->array[i];
new_array[array_length] = newItem;
// Releasing the memory of array
if (this->array_length != 0)
{
delete[] this->array;
this->array = nullptr;
}
this->array_length += 1;
this->array = new_array;
}
template<typename T>
void Utils::DynamicArray<T>::RemoveItem(int index)
{
T* new_array = new T[this->array_length - 1];
int temp_index = 0;
for (size_t i = 0; i < this->array_length; i++)
{
if (i != index)
{
new_array[temp_index] = this->array[i];
temp_index++;
}
}
// Releasing the memory of array
delete[] this->array;
this->array = nullptr;
this->array_length -= 1;
this->array = new_array;
}
template <typename T>
T& Utils::DynamicArray<T>::GetItem(int index)
{
return this->array[index];
}
template<typename T>
T& Utils::DynamicArray<T>::operator[](int index) const
{
return this->array[index];
}
template <typename T>
void Utils::DynamicArray<T>::ResetArray(T resetValue)
{
for (int i = 0; i < this->array_length; i++)
this->array[i] = resetValue;
}
template <typename T>
void Utils::DynamicArray<T>::SetItem(const int& index,const T& newValue)
{
this->array[index] = newValue;
}
main function:
#include <iostream>
#include "DynamicArray.h"
int main()
{
Utils::DynamicArray<Utils::DynamicArray<double>> outputs;
Utils::DynamicArray<double> singleOutput;
singleOutput.AddItem(1);
singleOutput.AddItem(1);
outputs.AddItem(singleOutput);
}
Output given when running the program:
before del2
after del
before del1
before del2
free(): double free detected in tcache 2
Aborted (core dumped)
Any ideas? No matter what I tried nothing worked..
You failed to write proper copy constructor and assignment operators:
DynamicArray(DynamicArray const& rhs); // copy constructor
DynamicArray& operator=(DynamicArray const& rhs); // copy assignment
When you don't write these yourself, they are generated with shallow copy semantics. Since your class "owns" a pointer, if you shallow copy it, then two instances o DynamicArray both own the same pointner, and when one is destroyed, it destroys the data pointed to by the other. And when the other is destroyed, you get a double free.
To write these you need to allocate memory and do a full copy.
(You also would eventually want to write a move constructor, and move assignment operator.)
The element declared on the stack in main() is also copied into the other DynamicArray. The double free occurs when the stack of main is cleaned up: first delete is in the destructor of singleOutput, and the second delete is in the destructor of outputs, which holds an element that has the same pointer as singleOutput.
You also leave your "array" member uninitialized in the default constructor. That does not set it to zero, it leaves garbage in it. (Which could be zero, but might not be.)

Conversion Issues relating to templates (c++)

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

how to implement efficient add in C++ templated list class

Suppose we have a templated c++ list class. Yes, vector exists, but the point is to know how to handle this problem.
The Constructor allocates a block of n objects of type T but does not initialize because they are not used yet.
In the add method, we wish to copy in a new object, but using operator = is not possible because operator = would first destroy the existing object, which was never initialized. How does one copy in an object into data[used] ?
#include <string>
template<typename T>
class DynArray {
private:
int capacity;
int used;
T* data;
public:
DynArray(int initialCap) : capacity(initialCap), used(0), data((T*)new char[sizeof(T)*capacity]) {}
void add(const T& e) {
//TODO: if the dynarray is full, grow
data[used++] = e; //ERROR! Should use copy constructor!!!
}
};
int main() {
DynArray<std::string> a(5);
a.add(std::string("abc"));
}
You should use placement new:
void add(const T& e) {
//TODO: if the dynarray is full, grow
new (data + used) T(e);
used++;
}
Placement new constructs an object in already allocated memory.
For what you are attempting to do, you need to call T's copy constructor using placement-new. And don't forget to implement the Rule of 3/5/0 as well:
template<typename T>
class DynArray {
private:
int capacity;
int used;
T* data;
public:
DynArray(int initialCap = 0) : capacity(0), used(0), data(0) {
reserve(initialCap);
}
DynArray(const DynArray &src) : capacity(0), used(0), data(0) {
reserve(src.capacity);
for(int i = 0; i < src.used; ++i) {
add(src.data[i]);
}
}
// C++11 and higher only...
DynArray(DynArray &&src) : capacity(src.capacity), used(src.used), data(src.data) {
src.capacity = src.used = 0;
src.data = 0;
}
~DynArray() {
clear();
delete[] reinterpret_cast<char*>(data);
}
DynArray& operator=(const DynArray &rhs) {
if (&rhs != this) {
DynArray(rhs).swap(*this);
}
return *this;
}
// C++11 and higher only...
DynArray& operator=(DynArray &&rhs) {
DynArray(std::move(rhs)).swap(*this);
return *this;
}
void swap(DynArray &other) {
std::swap(data, other.data);
std::swap(used, other.used);
std::swap(capacity, other.capacity);
}
void clear() {
resize(0);
}
void reserve(int newCap) {
// TODO: round up newCap to an even block size...
if (newCap <= capacity) return;
T *newData = reinterpret_cast<T*>(new char[sizeof(T) * newCap]);
for(int i = 0; i < used; ++i) {
new (newData + i) T(data[i]);
}
delete[] reinterpret_cast<char*>(data);
data = newData;
capacity = newCap;
}
void resize(int newSize) {
if (newSize < 0) newSize = 0;
if (newSize == used) return;
if (newSize > used) {
reserve(newSize);
for(int i = used; i < newSize; ++i) {
new (data + i) T();
++used;
}
}
else {
for(int i = used-1; i >= newSize; --i) {
data[i]->~T();
--used;
}
}
}
void add(const T& e) {
if (used == capacity) {
reserve(capacity * 1.5);
}
new (data + used) T(e);
++used;
}
};
#include <string>
int main() {
DynArray<std::string> a(5);
a.add("abc");
}
The DynArray class has a type of T, so you should simply allocate an array of type T with size of initialCap, which is simply
new T[initialCap];
For built-in types, e.g. int, the elements are left uninitialized.
For others, like string, the default constructor of T is called to initialize the elements.
In the add method, we wish to copy in a new object, but using operator = is not possible because operator = would first destroy the existing object
data[used++] = e; This is perfectly fine. It assigns e to data[used] - calls the assignment operator of the string, and it won't cause any troubles. However, when your array grows, you would need to allocate new arrays with double capacity, copy over the elements, and destroy the old data.

C++ struct constructor error

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];
};