I am trying to implement a dynamic array:
template <typename Item>
class Array {
private:
Item *_array;
int _size;
public:
Array();
Array(int size);
Item& operator[](int index);
};
template <typename Item>
Array<Item>::Array() {
Array(5);
}
template <typename Item>
Array<Item>::Array(int size) {
_size = size;
_array = new Item [size];
for (int i = 0; i < size; i++)
cout << i << " " << _array[i] << " " << &_array[i] << endl;
}
template <class Item>
Item& Array<Item>::operator[](int index) {
if (index < 0 || index > _size-1)
cout << "this: " << this << ". Index out of range" << endl;
return _array[index];
}
When used like this, it works as expected, i.e. prints 5:
Array< int > testArray(5);
testArray[0] = 5;
cout << testArray[0] << endl;
However, I would like to use the class for a two-dimensional dynamic array. I thought that the following would just magically work and print 5...
Array< Array<int> > testArray(5);
testArray[0][0] = 5;
cout << testArray[0][0] << endl;
...but it does not work. It crashes when I try to set the value at [0][0]. The debugger shows me that this has _size set to 0 and _array to NULL. this at that point points to the first element of the _array of the last created Array instance.
One of the things I don't get is when the "inner" array calls its constructor. Stepping through the code, I see that Array(int size) is called once and Array() five times. I would like to create the inner array with a specific size, but using Array< Array<int>(10) > testArray(5) does not compile.
Could you provide me with some insight on this? It seems I could not quite wrap my head around templates yet...
You cannot chain constructor calls in C++. Your first constructor implementation does nothing, so the 5 instances contained in the parent Array end up being uninitialized, resulting in undefined behavior.
To fix, you can either add a default value to the size parameter of the other constructor, or factor out the initialization logic in a separate (private) function, and call it from both constructors.
EDIT: The reason why the first constructor does nothing is that the line
Array(5)
does not call the constructor of the current instance, but instead allocates a new (unnamed) temporary Array instance, which is immediately destructed at the end of the line.
Use default value for constructor to call it without argument i.e. Array(int index = 5);
Please check this:
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3
Can one constructor of a class call another constructor of the same class to initialize the this object?
You cannot call another ctor from your default ctor . If you want to have a default value you can combine the two into one.
template <typename Item>
Array<Item>::Array(int size = 5) {
_size = size;
_array = new Item [size];
for (int i = 0; i < size; i++)
cout << i << " " << _array[i] << " " << &_array[i] << endl;
}
However if you still prefer to have the two ctor then you can move the implementation to a private _setup function that can be used from both like this.
template <typename Item>
Array<Item>::Array() {
_setup(5);
}
template <typename Item>
Array<Item>::Array(int size) {
_setup(size);
}
template <typename Item>
void Array<Item>::_setup(int size) {
_size = size;
_array = new Item [size];
for (int i = 0; i < size; i++)
cout << i << " " << _array[i] << " " << &_array[i] << endl;
}
Edited to remove invalid initializer for newed array.
Related
Excuse me in advance if I'm not explaining this clear..
Okay so I have declared a hash table using a vector like so:
> class HashTable{
private:
vector<string> arrayofbuckets[100];
public:
void insertelement(string input);
void deleteelement(string remove);
bool lookupelement(string search);
int tablesize();
> }; // end of class
I have also creating a menu using a switch statement to insert elements into the hash table:
> case 'I':
{
cout << " Which element would you like to insert?: ";
cin >> Element;
hash.insertelement(Element);
}
break;
It then gets passed on to this function:
void HashTable::insertelement(string input){
int hashValue = 0;
for(int i = 0; i<input.length(); i++){
hashValue = hashValue + int(input[i]);
}
hashValue = hashValue % 100;
arrayofbuckets[hashValue].push_back(input);
cout << " The element " << input << " has been put into value " << hashValue << ends;
}
Does anyone have any idea how to write a function to obtain and display the size of the table?
The best way is to keep track of the size inside functions that should initialise or modify it:
HashTable::HashTable() : size_(0) { }
void HashTable::insertelement(string input){
...do all the existing stuff...
++size_;
}
// similarly --size_ inside deleteelement...
int HashTable::tablesize() const { return size_; }
Make sure you add an int size_; data member.
Do note that bool lookupelement(string search) const; and int tablesize() const; should be const - I've inserted the keyword here so you know where to put it, and used it above when defining tablesize().
If you were really determined to avoid an extra member variable, you could also do this...
int HashTable::tablesize() const {
int size = 0;
for (std::vector<std::string>& vs : arrayOfBuckets)
size += vs.size();
return size;
}
...but most users will expect a constant-time and fast size() function: they may call it every time through their loops, so keep it cheap.
I am a beginner programmer in school still, and I was assigned this problem:
"Make your own dynamic array template. It should allow creating contiguous arrays (filled with things of the same type) which you can extend without worrying about running out of space.
Do one version using malloc and free.
Do one version using new and delete."
So far this is what I have:
#include <iostream>
#include <sstream>
#include "Array.h"
using namespace std;
int main(){
Array<int> *testArray = new Array<int>(5);
testArray->initArray();
testArray->printArray();
testArray->addData(7);
testArray->printArray();
return 0;
}
And here is the "Array.h" file:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
template<typename T>
class Array{
public:
Array(int size){
size = size;
data = new T[size];
};
Array<T> *addData(T dataToAdd){
Array <T> *tmp = new Array <T> (this->size);
tmp->data = this->data;
Array <T> *newData = new Array<T> (this->size + 1);
for (int i = 0; i < this->size + 1; ++i){
if (i < this->size){
//newData->data[i] = tmp->data[i];
newData->setData(tmp->getData()[i], i);
}
else{
//newData->data[i] = dataToAdd;
newData->setData(dataToAdd, i);
}
}
return newData;
};
void initArray(){
for (int i = 0; i < this->size; ++i){
//this->data[i] = i;
this->setData(i, i);
}
};
void printArray(){
ostringstream oss;
string answer = "";
for (int i = 0; i < this->size; ++i){
oss << this->data[i] + " ";
//cout << this->data[i] << " ";
}
answer = oss.str();
cout << answer << "asdf" << endl;
};
T* getData(){
return this->data;
}
int getSize(){
return this->size;
}
void setData(T data, int index){
this->getData()[index] = data;
}
private:
int size;
T* data;
};
So far what SHOULD happen in my main file is there should be an array of 5 ints, that are initialized to 0,1,2,3,4 from the initArray function.
Then it should print out the array, showing "0 1 2 3 4," add another "7" to it, then print the new array out showing "0 1 2 3 4 7."
For some reason, and I think it has something to do with losing data somehow when going between the two files, the field "data" of my Array class is not being properly changed.
I even hardcoded a test for this in main where I wrote a for loop using the setData function that initializes the Array to "0 1 2 3 4," and then manually printed out these values with another for loop, but the output was only "0 0 0 0 0."
Right now, as the code is, the output is:
asdf
asdf
As it was outputting whitespace before so I added the "asdf"'s to see if my printArray worked at all.
To sum up, why is the data in my private field "data" not being properly stored? I am very new to programming in c++ and any advice would be greatly appreciated. Thank you for your time, and if there is anything you do not understand please ask for clarification and I will do my best.
EDIT: problem solved! Thank you everyone who helped, the issue was with my constructor and how I was calling my functions in main.
One issue is your constructor:
Array(int size){
size = size;
data = new T[size];
};
The way you have it, you're just assigning your size argument to itself, which has no effect. One way to fix it would be to use a different name for the argument:
Array(int size_arg){
size = size_arg;
data = new T[size_arg];
};
However, the preferred way is to use the constructor initializer syntax:
Array(int size) : size(size), data(new T[size]) {};
With the constructor initializer syntax, the compiler knows that you are trying to initialize specific members and doesn't get confused between the argument name and the member name.
This is a class template for an Array. I overloaded the [ ] operator in hopes it would fix the "out of bounds" issue. The print outs work well, except if it falls out of range, the compiler enables the range by default and it displays a 6 digit number.
Perhaps looking for a better way to initialize the arrays with the appropriate element number for a better check and if it does fall out of range when looking up the element, display an error.
// implement the class myArray that solves the array index
// "out of bounds" problem.
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
template <class T>
class myArray
{
private:
T* array;
int begin;
int end;
int size;
public:
myArray(int);
myArray(int, int);
~myArray() { };
void printResults();
// attempting to overload the [ ] operator to find correct elements.
int operator[] (int position)
{if (position < 0)
return array[position + abs(begin)];
else
return array[position - begin];
}
};
template <class T>
myArray<T>::myArray(int newSize)
{
size = newSize;
end = newSize-1;
begin = 0;
array = new T[size] {0};
}
template <class T>
myArray<T>::myArray(int newBegin, int newEnd)
{
begin = newBegin;
end = newEnd;
size = ((end - begin)+1);
array = new T[size] {0};
}
// used for checking purposes.
template <class T>
void myArray<T>::printResults()
{
cout << "Your Array is " << size << " elements long" << endl;
cout << "It begins at element " << begin << ", and ends at element " << end << endl;
cout << endl;
}
int main()
{
int begin;
int end;
myArray<int> list(5);
myArray<int> myList(2, 13);
myArray<int> yourList(-5, 9);
list.printResults();
myList.printResults();
yourList.printResults();
cout << list[0] << endl;
cout << myList[2] << endl;
cout << yourList[9] << endl;
return 0;
}
First of all, your operator[] is not correct. It is defined to always return int. You will get compile-time error as soon as you instantiate array of something, that is not implicitly convertible to int.
It should rather be:
T& operator[] (int position)
{
//...
}
and, of course:
const T& operator[] (int position) const
{
//you may want to also access arrays declared as const, don't you?
}
Now:
I overloaded the [ ] operator in hopes it would fix the "out of bounds" issue.
You didn't fix anything. You only allowed clients of your array to define custom boundaries, nothing more. Consider:
myArray<int> yourList(-5, 9);
yourList[88] = 0;
Does your code check for out-of-bounds cases like this one? No.
You should do it:
int operator[] (int position)
{
if((position < begin) || (position > end)) //invalid position
throw std::out_of_range("Invalid position!");
//Ok, now safely return desired element
}
Note, that throwing exception is usually the best solution in such case. Quote from std::out_of_range doc:
It is a standard exception that can be thrown by programs. Some components of the standard library, such as vector, deque, string and bitset also throw exceptions of this type to signal arguments out of range.
An better option to redefining an array class is to use the containers from the std library. Vector and array(supported by c++11). They both have an overloaded operator [] so you can access the data. But adding elements using the push_back(for vector) method and using the at method to access them eliminates the chance or getting out of range errors, because the at method performs a check and push_back resizes the vector if needed.
So for school I have to make a Node class that holds a time and a number (it's used for an insertion sort later). I'm still new to C++ so I'm probably doing something wrong here, but whenever I call my GetNumber() method, it will return only the number of the last Node that was made. My code is below:
Node.cpp
#include "Node.h"
int n, t;
Node::Node(int number, int time)
{
n = number;
t = time;
}
Node::~Node(void)
{
}
int Node::GetTime(void)
{
return t;
}
int Node::GetNumber(void)
{
return n;
}
And in main:
Node f(123, GetTickCount());
for (int i = 0; i < 1000; i++){}
Node g(124, GetTickCount());
for (int i = 0; i < 1000; i++){}
Node d(111, GetTickCount());
cout << f.GetNumber() << " " << f.GetTime()<<endl;
cout << g.GetNumber() << " " << g.GetTime()<<endl;
cout << d.GetNumber() << " " << d.GetTime()<<endl;
And the output:
111 168921894
111 168921894
111 168921894
int n, t;
You are declaring n and t as global variables - they don't belong to any particular object. All Nodes will see the same n and t objects.
You should be declaring these as members of Node:
class Node {
// ...
int n, t;
// ...
};
The problem here is you are using file level variables as the storage for all Node values. Instead you need to store them as instance fields in the type
class Node {
...
private:
int n;
int t;
};
Once those fields are defined delete the declaration at the top of the file for n and t
You didn't define "n" and "t" in the class and so they are global and only the last one to change is the one that is relevant.
So searching to see if someone has already asked this I see lots of questions about iterating over arrays. But what I've got is an array of iterators. Essentially here's what I'm up to:
I have a sorted std::list of a custom object. The object just contains an int and a double, and has methods for the sorts of things you would expect (constructors, setters, getters, operator< to make it sortable by the double, a toSting() method). That all works, including sorting.
Now I want a bunch of iterators that point into the list at different points. There will be one to the head of the list, one to the tail and several pointing into various points in the middle. I'm doing this using an old-style array (this may be the problem - I'll try it with a std::array, but I still want to understand why this hasn't worked). So I've got a subroutine that initializes this array. It almost works. I can build the array and output from within the subroutine and everything looks good. Outputting from outside the subroutine the last element of the array has changed and no longer appears to point into the list. Here's the relevant code:
using namespace std;
#include <iostream>
#include <list>
#include <cmath>
#include <algorithm>
#include "random.h"
#include "Double_list_struct.h"
/**********************************Subroutine declarations***************************/
template <typename Tplt>
void output_list(list<Tplt> to_out);
template <typename Tplt>
void initialize_list(list<Tplt> &alist, int size);
template <typename Tplt>
void initialize_iter_array(typename list<Tplt>::iterator* itar, int size, list<Tplt> alist);
/***************************************Main routine*******************************/
int main(void)
{
int list_size = 16;
// Make the list that will be tested.
list<Double_list_struct> list_to_play_with;
initialize_list(list_to_play_with, list_size);
list_to_play_with.sort();
cout << "Sorted list is: " << endl;
output_list(list_to_play_with);
// Make an array of list<Double_list_struct>::iterator of size floor(sqrt(N))
int iter_array_size = floor(sqrt(list_size));
list<Double_list_struct>::iterator* iter_array;
iter_array = new list<Double_list_struct>::iterator[iter_array_size];
// Initialize the iterators in iter_array to point to roughly evenly spaced locations in the list
initialize_iter_array(iter_array, iter_array_size, list_to_play_with);
for (int i = 0; i < iter_array_size; i++)
{
cout << "In main routine, iter_array[" << i << "]:" << (*(iter_array[i])).toString() << endl;
}
cout << "Reset it, and redo the output loop??" << endl;
iter_array[iter_array_size-1] = list_to_play_with.end();
iter_array[iter_array_size-1]--;
for (int i = 0; i < iter_array_size; i++)
{
cout << "In main routine, iter_array[" << i << "]:" << (*(iter_array[i])).toString() << endl;
}
}
/************************************************Subroutine code**************************************/
// Output all elements of a list to cout.
template <typename Tplt>
void output_list(list<Tplt> to_out)
{
...not important here
}
template <typename Tplt>
void initialize_list(list<Tplt> &alist, int size)
{
...not important here
}
template <typename Tplt>
void initialize_iter_array(typename list<Tplt>::iterator* itar, int size, list<Tplt> alist)
{
itar[0] = alist.begin();
itar[size-1] = alist.end();
itar[size-1]--; // Recall that .end() makes an iterator point *past* the end...
// Find out how big the list is
int listsize = 0;
for (typename list<Tplt>::iterator it = itar[0]; it != itar[size-1]; it++)
{
listsize = listsize + 1;
}
int spacing = floor(listsize/(size-1));
cout << "In initialize_iter_array(): created itar[0]: " << (*itar[0]).toString() << endl;
for (int i = 1; i < size-1 ; i++)
{
itar[i] = itar[i-1];
for (int j = 0; j < spacing; j++)
{
itar[i]++;
}
cout << "In initialize_iter_array(): created itar[" << i << "]: " << (*itar[i]).toString() << endl;
}
cout << "In initialize_iter_array(): created itar[" << size-1 << "]: " << (*itar[size-1]).toString() << endl;
}
This generates output
Sorted list is:
struct[15] = 0.135837
struct[1] = 0.200995
struct[12] = 0.217693
...SNIP...
struct[8] = 0.863816
struct[14] = 0.887851
struct[2] = 0.893622
struct[10] = 0.925875
In initialize_iter_array(): created itar[0]: struct[15] = 0.135837
In initialize_iter_array(): created itar[1]: struct[5] = 0.314127
In initialize_iter_array(): created itar[2]: struct[11] = 0.704419
In initialize_iter_array(): created itar[3]: struct[10] = 0.925875
In main routine, iter_array[0]:struct[15] = 0.135837
In main routine, iter_array[1]:struct[5] = 0.314127
In main routine, iter_array[2]:struct[11] = 0.704419
In main routine, iter_array[3]:struct[-1] = 6.21551e-71
Reset it, and redo the output loop??
In main routine, iter_array[0]:struct[15] = 0.135837
In main routine, iter_array[1]:struct[5] = 0.314127
In main routine, iter_array[2]:struct[11] = 0.704419
In main routine, iter_array[3]:struct[10] = 0.925875
So, you see, iter_array[3] is correct inside the initialization subroutine, but has "moved" after the subroutine exits. I then reset it from outside the subroutine, but obviously I'd like to not have to do that...
My best guess is that there is something subtle going on here with how the assignment operator works for iterators. But I'm very puzzled.
initialize_iter_array takes the list by value, which means it's putting iterators that point into the parameter copy of the list, not the original list. You probably meant to pass the list by const& instead.