I create a class Vector that contain two variables that are template variable, I am trying to build such a dictionary that tell mark of a specific student.
The problem is I am struggling dynamic allocating memory with template. I have to do this without map or STL help. Can you explain, how to allocate them properly.
#define DEF_CAPACITY 20
template <class U, class T>
class Vector {
protected:
T* _data;
U* _keys;
int _size; //size in use
int _capacity; //available capacity
public:
//constructors
Vector(int capacity = DEF_CAPACITY);
~Vector();
int getSize() const { return size; }
void insert(U key, T data);
T operator[](U key);
};
template<class U, class T>
inline Vector<U, T>::Vector(int capacity)
{
this->_capacity = capacity;
this->_size = 0;
}
template<class U, class T>
Vector<U, T>::~Vector()
{
if (_data)
delete[] _data;
if (_keys)
delete[] _keys;
}
template<class U, class T>
void Vector<U, T>::insert(U key, T data)
{
_keys[_size] = new U;
//Maybe I have to do something like that, but all options I test doesn't work
//keys[_size] = new U[Some size];
_keys[_size] = key;
_data[_size] = new T;
_data[_size] = data;
_size++;
}
template<class U, class T>
T Vector<U, T>::operator[](U key)
{
int index = 0;
for (int i = 0; i < size; i++)
if (_keys[i] == key)
index = i;
return _data[index];
}
int main() {
Vector<string, int> grades;
grades.insert("john", 90);
grades.insert("marc", 100);
grades.insert("ron", 87);
grades.insert("lynda", 95);
//...
grades.insert("Tome", 93);
//...
cout << grades["marc"] << endl;
cout << grades["lynda"] << endl;
cout << grades["john"] << endl;
return 0;
}
To allocate n elements of type T you use:
T* array = new T[n];
so to allocate space for your keys and values:
// be aware: this will call the constructor for each element!!!
_keys = new U[n];
_data = new T[n];
If your "Vector" has a fixed capacity, this should be done in your constructor:
template<class U, class T>
inline Vector<U, T>::Vector(int capacity)
: _data(new T[capacity]);
, _keys(new U[capacity]);
, _size(0);
, _capacity(capacity);
{
}
after that, you can insert key/value pairs like this:
template<class U, class T>
void Vector<U, T>::insert(const U& key, const T& data)
{
if(_size == _capacity)
throw std::out_of_range("no space left!!!");
_keys[_size] = key; // copy assignment
_data[_size] = data; // copy assignment
_size++;
}
This design will unnecessarily call constructors for unused keys and values.
You could also do this with malloc and free to prevent this, though I wouldn't recommend going that way and instead use the standard library.
Related
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.)
hello i want to create simple array class to get value and insert value like (array[0] = 4) and this is my program but i have problem to use [] = in same time for insert
template <typename Param>
class arr
{
private:
int Last_point = 0;
Param Data[];
public:
void& operator[]=(int Element_id, Param v)
{
Data[Element_id] = v;
}
Param& operator[] (int Element_id)
{
return Data[Element_id];
}
};
void main()
{
arr <int> Array;
Array[1] = 555;
cout << "Is(" << to_string(Array[1]) << ")" << endl;
system("pause");
}
is there any operator like ([]=)? or for this, i have to use which methods? also i want to get value if just used []
The syntax you are attempting for the operator[] functions is quite wrong. You need something like:
// Version for non-const objects
Param& operator[](std::size_t i)
{
return Data[i];
}
// Version for const objects
Param const& operator[](std::size_t i) const
{
return Data[i];
}
If you want to support arrays whose sizes are known at compile time, you can use:
template <typename Param, std::size_t N>
class arr
{
private:
Param Data[N];
public:
Param& operator[](std::size_t i)
{
return Data[i];
}
Param const& operator[](std::size_t i) const
{
return Data[i];
}
};
If you want to support arrays whose sizes are known at run time, you can use the following. However, you need to be aware of The Rule of Three and make sure to implement the copy constructor and the copy assignment operator properly.
template <typename Param>
class arr
{
private:
Param* Data;
public:
arr(size_t size) : Data(new Param[size]) {}
~arr() { delete [] Data; }
Param& operator[](std::size_t i)
{
return Data[i];
}
Param const& operator[](std::size_t i) const
{
return Data[i];
}
};
Foo& operator[] is sufficient for reading and writing.
Include the size of the array as a template parameter, or replace Param[] with std::vector<Param>.
Use size_t instead of int for array index types.
You don't need to wrap Array[1] in to_string for output.
Don't use void main! The standard says main must be int.
void& is not valid C++ either.
#include <iostream>
using namespace std;
template <typename Param, size_t Size> class arr {
private:
Param Data[Size];
public:
Param &operator[](size_t Element_id) {
return Data[Element_id];
}
};
int main() {
arr<int, 3> Array;
Array[1] = 555;
cout << "Is(" << Array[1] << ")" << endl;
}
However, all that arr does in my snippet is be a less useful std::array!
I want to print the results of the work of my custom memory allocator for the STL map container. I want to get the memory allocation map printed.
I have a problem with get_allocator(). See the example.
The get_allocator() call gives the allocator for the initial pair<int,int>. It even creates it...
Is there a way to get the true allocator (the instance of Pool for RBtree) which gives the memory for the map's elements?
I am using gcc. Thanks.
#include <memory>
#include <map>
using namespace std;
class Pool {
//...
public:
Pool(unsigned n);
~Pool();
void* alloc();
void free(void*);
void print_mm(); //print pool map
//...
};
void* Pool::alloc() {
//...
}
//...
void Pool::print_mm() {
//...
}
template<class T> class Pool_alloc : public allocator<T> {
static Pool pool;
public:
template<class U> struct rebind {
typedef Pool_alloc<U> other;
};
template<class U> Pool_alloc(const Pool_alloc<U>&) {}
Pool_alloc() {}
T* allocate(size_t, void*);
void deallocate(T*, size_t);
void print_mm() {pool.print_mm();}
};
template<class T> Pool Pool_alloc<T>::pool(sizeof(T));
template<class T> T* Pool_alloc<T>::allocate(size_t n, void* = 0) {
//...
return p;
}
template<class T> void Pool_alloc<T>::deallocate(T* p, size_t n) {
//...
}
main() {
map<int, int, less<int>, Pool_alloc<pair<int, int> > > m;
m[144] = 12;
m.get_allocator().print_mm(); //doesn't work - it gives the wrong allocator :-(
}
And the next is the complete code of the example - its base is taken from the famous Bjarne Stroustrup's book. ;-)
#include <iostream>
#include <memory>
#include <map>
using namespace std;
class Pool {
struct Link {Link *next;};
struct Chunk {
static const unsigned size = 8192 - sizeof(Chunk*); //page boundary
Chunk *next;
char mem[size];
} *chunks;
Link *head; //pointer to first free link
Pool(Pool&); //disable
void operator=(Pool&); //disable
void grow();
public:
const unsigned int atomsize;
Pool(unsigned n); //n - number of atoms
~Pool();
void* alloc(); //for one atom
void free(void*);
void print_mm(); //print pool memory map
};
void* Pool::alloc() {
if (head == 0) grow();
Link *p = head;
head = p->next;
return p;
}
void Pool::free(void *b) {
Link *p = static_cast<Link*>(b);
p->next = head;
head = p;
}
Pool::Pool(unsigned sz): atomsize(sz < sizeof(Link*) ? sizeof(Link*) : sz) {
cout << "atom size = " << atomsize << " bytes\n";
head = 0;
chunks = 0;
}
Pool::~Pool() {
Chunk *p = chunks;
while (p) {
Chunk *q = p;
p = p->next;
delete q;
}
}
void Pool::grow() {
Chunk *p = new Chunk;
p->next = chunks;
chunks = p;
const unsigned noe = Chunk::size/atomsize;
char *start = p->mem, *last = start + (noe - 1)*atomsize;
for (char *p = start; p < last; p += atomsize)
((Link*)p)->next = (Link*)(p + atomsize);
((Link*)last)->next = 0;
head = (Link*)start;
}
void Pool::print_mm() {
cout << "The pool memory map\n";
///...
}
template<class T> class Pool_alloc : public allocator<T> {
static Pool pool; //static for STL
public:
template<class U> struct rebind {
typedef Pool_alloc<U> other;
};
template<class U> Pool_alloc(const Pool_alloc<U>&) {}
Pool_alloc() {}
T* allocate(size_t, void*);
void deallocate(T*, size_t);
static void print_mm() {pool.print_mm();}
};
template<class T> Pool Pool_alloc<T>::pool(sizeof(T));
template<class T> T* Pool_alloc<T>::allocate(size_t n, void* = 0) {
T* p;
if (n == 1)
p = static_cast<T*>(pool.alloc());
else
p = static_cast<T*>(allocator<T>::allocate(n)); //STL level
//p = static_cast<T*>(operator new (sizeof(T)*n)); //OS level
return p;
}
template<class T> void Pool_alloc<T>::deallocate(T* p, size_t n) {
if (n == 1)
pool.free(p);
else
allocator<T>::deallocate(p, n); //STL level
//operator delete(p); //OS level
}
main() {
map<int, int, less<int>, Pool_alloc<pair<int, int> > > m;
m.insert(pair<int,int>(7, 8));
for (int i(0); i < 200; ++i)
m[i*i] = 2*i;
m.erase(169);
m.erase(121);
m[5] = 88;
cout << m[7] << '-' << m[5] << '-' << m.size() << endl;
m.get_allocator().print_mm(); //doesn't work - it gives the wrong allocator :-(
}
Try this:
template<class T, Pool* pool> class Pool_alloc : public allocator<T> {
public:
template<class U> struct rebind {
typedef Pool_alloc<U, pool> other;
};
This requires your Pool support data of different sizes.
Alternatively, replace Pool with Pool<sizeof(T)>, maybe using the static method trick to allocate the singleton instance, then you can at least find the various sized allocators. (They could register themselves with a global pool of pools so you can find them later).
Your pool allocator can then be smart enough to use different size chunks for different sized data requested. Or not, as you want.
There are some Classes: Array, NumericArray. Array is a template class, and NumericArray is a class inherited from Array designed to take int, double, etc.
Part of Header of NumericArray:
template <class T = int>
class NumericArray : public Array<T>{
private:
T* m_data;
int size;
public:
NumericArray<T> operator * (T factor)const;
};
here are constructors and some functions of NumericArray:
template <class T>
NumericArray<T>::NumericArray(){
m_data = new T[10];
size = 10;
}
template <class T>
NumericArray<T>::NumericArray(int n){
m_data = new T[n];
size = n;
}
template <class T>
NumericArray<T>::NumericArray(const NumericArray<T>& s_data){
m_data = new T[s_data.size];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = s_data.m_data[i];
}
size = s_data.Size();
}
/* Destructor */
template <class T>
NumericArray<T>::~NumericArray(){
delete [] m_data;
}
template <class T>
NumericArray<T> NumericArray<T>::operator * (T factor)const{
NumericArray<T> temp(size);
for (int i = 0; i<size;i++){
temp.m_data[i] = (*this)[i] *factor;
}
return temp;
}
And when I call it in the main(), something weird happens. For example:
NumericArray<int> intArray1(10);
NumericArray<int> intArray2;
for(int i =0; i<10;i++){
intArray1[i] = i;
intArray2[i] = i;
}
The 2 arrays do contain numbers 0-9, but if I call
NumericArray intArray4 = intArray1*2;
intArray4 consists of zero(0)s. It seems that the default constructor is called in the function and passed to Array4. And after the operator, Array1 and Array2 are still numbers 0-9
Below are the related code of Array
template class Array{
private:
T* m_data;
int size;
public:
Array(); // constructor
Array(int n); // constructor
Array(const Array<T>& s_data); //Copy Constructor
virtual ~Array(); // destructor
void SetElement(int i, const T& source);
T& GetElement(int i)const;
int Size() const;
int DefaultSize()const;
void DefaultSize(int n);
// Operator overloading
Array<T>& operator = (const Array<T>& source) ;
T& operator [](int i);
const T& operator [] (int i) const;
};
template <class T>
Array<T>::Array(){
// default constructor
m_data = new T[defaultSize]; // initialize T*
size = defaultSize; // initialize integer
}
template <class T>
Array<T>::Array(int n){
// Constructor with arguments
m_data = new T[n];
size = n;
}
template <class T>
Array<T>::Array(const Array<T>& s_data){
// Copy constructor
m_data = new T[s_data.Size()];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = T( s_data.m_data[i]);
}
size = s_data.Size();
defaultSize = s_data.Size();
}
template <class T>
T& Array<T>::operator [](int i) {
if (i > size|| i<0){
OutOfBoundsException a;
throw a;
}
return m_data[i];
}
Not sure if provided enough information. Any hint is greatly appreciated.
The easiest way to access base class data members when the base is a (dependent) class template, is a using declaration like this:
#include <iostream>
using namespace std;
template< class Item >
class Base
{
protected:
Item item_;
Base( Item const& v ): item_( v ) {}
};
template< class Item >
class Derived
: public Base< Item >
{
protected:
using Base<Item>::item_;
public:
auto value() const -> Item { return item_; }
Derived( Item const& v ): Base<Item>( v ) {}
};
auto main() -> int
{
Derived<int> const x( 42 );
cout << x.value() << endl;
}
Alternatively you can qualify the access, e.g. this->item_ or Base<Item>::item_.
That said, it’s usually not a good idea to let derived classes access base class data members directly.
Here is the problem: both NumericArray and Array have
T* m_data;
int size;
The function Array::operator[] is called from Array which uses Array::m_data, however the NumericArray::operator* sets NumericAray::m_data. It probably is working as you would expect, but you are reading from the wrong pointer.
Remove the members from NumericArray and make the members protected instead of private in Array. The second part is optional if the implementation is changed a little bit.
I'm starting to learn c++ but I'm stuck in the destructor. We need to implement a vector and this is what I have so far.
#include<string.h>
#include<cassert>
#include<iostream>
using namespace std;
template<class T>
class Vector {
template<class U> friend ostream& operator<<(ostream&, const Vector<U>&);
private:
T* data;
unsigned len;
unsigned capacity;
public:
Vector(unsigned = 10);
Vector(const Vector<T>&);
virtual ~Vector(void);
Vector<T>& operator =(const Vector<T>&);
bool operator==(const Vector<T>&);
T& operator[](unsigned);
};
//PROBLEM!
template <class T>
~ Vector() {
delete data;
}
template<class T>
Vector<T>::Vector(unsigned int _capacity)
{
capacity = _capacity;
len = _capacity;
data = new T[_capacity];
}
template<class T>
Vector<T>::Vector(const Vector<T> & v)
{
len = v.len;
capacity = v.capacity;
data = new T[len];
for (unsigned int i = 0; i < len; i++)
data[i] = v.data[i];
}
template<class T>
Vector<T> & Vector<T>::operator = (const Vector<T> & v)
{
delete[ ] data;
len = v.len;
capacity = v.capacity;
data = new T [len];
for (unsigned int i = 0; i < len; i++)
data[i] = v.data[i];
return *this;
}
template<class T>
bool Vector<T>::operator == (const Vector<T> & v)
{
bool check = true;
check &= (len == v.len);
if (!check) return false;
check &= (capacity == v.capacity);
if (!check) return false;
for (unsigned int i = 0; i < len; i++) {
check &= (data[i] == v.data[i]);
if (!check) return false;
}
return true;
}
template<class T>
T& Vector<T>::operator[](unsigned int index)
{
return data[index];
}
The interface is given and I need to implement it. But this is so different from C and Java, that I'm a bit lost.
In the second exercise we need to implement something like this using a) the previous Vector implementation as derived class and b) the Vector as composition class, so maybe we will use the virtual destructor in one of the approaches?
void testAssociativeArray() {
AssociativeArray<String, int> table;
table["abc"] = 15;
table["jkl"] = 12;
table["xyz"] = 85;
assert(table["jkl"], 12);
}
template<class P, class Q>
class Pair {
P p;
Q q; public:
Pair(const P& _p = P(), const Q& _q = Q()): p(_p), q(_q) {}
P& objectP() {return p;}
Q& objectQ() {return q;}
};
First off, why do you think that the destructor should be virtual? Are you using polymorphism?
Second, you are using delete incorrectly for your array.
Since you used:
data = new T[length];
You must use the array syntax:
delete [] data;
Third, you need to put the namespace in front of all of your class function definitions:
template <class T>
Vector<T>::~Vector()
{
delete [] data;
}
And just for your information, you declare the destructor like so...
virtual ~Vector(void);
As I mentioned, virtual is unnecessary unless you are using this class as a base or derived class in a polymorphic manner. For more information on when you need to use virtual destructors, look at the answer to this question.
In addition, the void in the parameters is also unnecessary. This used to be required in old C standard, but it is not in C++.
You should be able to declare it like so:
~Vector();
If you define AssociativeArray<P,Q> with a has-a relationship to Vector<T>, then you can simply make the class contain a Vector<Pair<P,Q> >. Declaring virtual methods in this case, are not needed, but can still be used--with some extra overhead.
If you define AssociativeArray<P,Q> with a is-a relationship to Vector<Pair<P,Q> >, then you should define some virtual methods in Vector<T>, including a virtual destructor.
The use of virtual methods only matters when using objects polymorphically through pointers and references. See this page.
AssociativeArray<String,Int>* myDerivedMap = new AssociativeArray<String,Int>();
delete myDerivedMap; //NO virtual methods necessary here. using a pointer to derived class
Vector<Pair<String,Int> >* myBaseMap = new AssociativeArray<String,Int>();
delete myBaseMap; //virtual methods ARE necessary here. using a pointer to base class
template<class T>
Vector<T>::~Vector()
{
delete [] data;
}
Note that you must use delete [] and not delete
Should be
template <class T>
Vector<T>::~Vector() {
delete[] data;
}