c++ template method syntax issue - c++

I am trying to create a method that creates an array of double the size given, then fills the first half of the array with the original values and the second half with the original values in reverse order. I have completed this but the next task is to make the method accept arrays of generic type and i'm stuck and not sure where to go from here
my code so far:
template <typename T>
T& *copy_and_reverse(T& *a, int length) {
T& *result = new T&[length*2];
int w = length-1;
for (int i = 0; i < length * 2; i++) {
if (i < length) {
result[i] = a[i];
} else {
result[i]=a[w];
w--;
}
}
return result;
}
int main() {
double numbers[5]={8.364,4.3,5.3,9.6,7.645};
int size=sizeof numbers/sizeof(double);
double *pointertonumbers;
pointertonumbers=copy_and_reverse(numbers, size);
for(int i=0;i<size*2;i++){
cout<<pointertonumbers[i]<<"\n";
}
}
at the moment the code does not work as i get multiple "error: cannot declare pointer to 'T&'"

If the compilre says that it cannot declare pointer to T& then try to declare a reference to T *. Maybe the compiler will be happy in this case.:)
T * copy_and_reverse( const T *a, int length) {
T *result = new T[length*2];
As for me I would use standard algorithm std::copy. For example
template <typename T>
T * copy_and_reverse( const T *a, size_t length)
{
T *result = new T[ 2 * length ];
std::copy( a, a + length, result );
std::copy( a, a + length, reverse_iterator<int *>( result + 2 * length ) );
return result;
}

First, you cannot create pointer to reference (what you are trying to do). Reference to a pointer would be T* &a. And you should not return pointer to a reference (and reference to a pointer either, as it will create dangling reference)
Actually, it's better to be on a safe side and accept a reference to an array.
T* copy_and_reverse(T (&a) [N]) {
T *result = new T[N*2];
size_t w = N-1;
for (size_t i = 0; i < N * 2; i++) {
if (i < N) {
result[i] = a[i];
} else {
result[i]=a[w];
w--;
}
}
return result;
}
int main() {
double numbers[5]={8.364,4.3,5.3,9.6,7.645};
int size=sizeof numbers/sizeof(double);
double *pointertonumbers;
pointertonumbers=copy_and_reverse(numbers);
for(int i=0;i<size*2;i++){
std::cout<<pointertonumbers[i]<<"\n";
}
delete [] pointertonumbers;
}
This still have issues. You should not forget to delete result of a function. With C++11 you can rewrite it really safe with std::arrays:
std::array<T, N*2> copy_and_reverse(const std::array<T, N>& orig) {
std::array<T, N*2> result;
std::copy(orig.begin(), orig.end(), result.begin());
std::copy(orig.begin(), orig.end(), std::reverse_iterator<typename std::array<T, N*2>::iterator>(result.end()));
return std::move(result);
}
int main() {
std::array<double, 5> numbers = {{8.364,4.3,5.3,9.6,7.645}};
auto pointertonumbers(copy_and_reverse(numbers));
for(size_t i=0;i<pointertonumbers.size();i++){
std::cout<<pointertonumbers[i]<<"\n";
}
}
Here you get rid of pointers (and all its issues) completely.

Related

Template specialization not working with char*

I am trying to create a template which will add an element to the end of an array (after resizing). I want to specialize it so that if the type is char*, it will include a null byte at the end.
Here is my main:
int main()
{
int* arrI = nullptr;
arrI = insertAtend(arrI, 0, 1); //1
std::cout << arrI[0];
delete[] arrI;
char* arrC = nullptr;
arrC = insertAtend(arrC, 0, 'a'); //a
std::cout << arrC;
delete[] arrC;
return 0;
}
And here are the templates:
template<typename T>
T* insertAtend(T* arr, int size, const T toAdd)
{
T* temp = new T[++size];
if (arr)
{
for (int i = 0; i < size; i++)
{
temp[i] = arr[i];
}
delete[] arr;
}
arr = new T[size + 1];
if (temp)
{
for (int i = 0; i < size; i++)
{
arr[i] = temp[i];
}
}
delete[] temp;
arr[size - 1] = toAdd;
return arr;
}
template<>
char* insertAtend<char*>(char* a, int s, const char* d)
{
return a;
}
Obviously without logic, but I am getting an error:
C2912 "Error C2912 explicit specialization 'char *insertAtend<char>(char *,int,const char *)' is not a specialization of a function template"
You're simply confusing the base type (char) with the pointer type (char *).
Change your specialization to this:
template<>
char* insertAtend<char>(char* a, int s, const char d)
{
return a;
}

C++ Dynamic array has not requested size

While creating a custom class for STL Multimap, I came across an unintended behaviour where dynamic arrays created by new operator are not of the size between []. In the following code, in a.Set(3, 'c') the arrays stored in newKey and newSize are of size one, when they should have size two. Using the debugger shows that in that lines index is equal to 1, so size should be two. Program does not produce any exception but it also does not output the expected result c.
As clarification, using the debugger shows that the problem occurs while setting the value at index 1 in newKey, newSize, newValue. It does not throw any kind of exception, but does not change any value either.
template<typename T>
void Copy(T const* _source, T* _destiny, unsigned long _size)
{
for (unsigned long i = 0; i < _size; i++)
{
_destiny[i] = _source[i];
}
}
template<typename T>
void CopyNew(T const* _source, T* _destiny, unsigned long _size)
{
T* target = new T[_size];
for (unsigned long i = 0; i < _size; i++)
{
target[i] = _source[i];
}
_destiny = target;
}
template<typename T1, typename T2>
class Multimap
{
public:
Multimap() {}
unsigned long Get(T1 const& _key, T2** _return)
{
for (unsigned long i = 0; i < this->keySize_; i++)
{
if (_key == this->key_[i])
{
CopyNew<T2>(this->value_[i], *_return, this->valueSize_[i]);
return i;
}
}
*_return = 0;
return this->keySize_;
}
unsigned long Get(T1 const& _key)
{
for (unsigned long i = 0; i < this->keySize_; i++)
{
if (_key == this->key_[i])
{
return i;
}
}
return this->keySize_;
}
int Set(T1 const& _key, T2 const& _value)
{
T2* target;
unsigned long index = this->Get(_key, &target);
if (target == 0)
{
T1* newKey = new T1[index + 1];
unsigned long* newSize = new unsigned long[index + 1];
T2** newValue = new T2*[this->keySize_ + 1];
if (this->keySize_ != 0)
{
Copy(this->key_, newKey, index);
delete[] this->key_;
Copy(this->valueSize_, newSize, index);
for (unsigned long i = 0; i < this->keySize_; i++)
{
newValue[i] = new T2[this->valueSize_[i]];
Copy(this->value_[i], newValue[i], this->valueSize_[i]);
delete[] this->value_[i];
}
delete[] this->valueSize_;
}
newKey[index] = _key;
newSize[index] = 0;
this->key_ = newKey;
this->valueSize_ = newSize;
this->value_ = newValue;
this->keySize_++;
}
unsigned long newSize = this->valueSize_[index]+1;
T2* newValue = new T2[newSize];
Copy(this->value_[index], newValue, newSize-1);
newValue[newSize-1] = _value;
this->valueSize_[index] = newSize;
this->value_[index] = newValue;
return newSize;
}
unsigned int GetSize()
{
return this->keySize_;
}
protected:
unsigned long keySize_ = 0;
unsigned long* valueSize_ = 0;
T1* key_ = 0;
T2** value_ = 0;
};
int main()
{
Multimap<int, char> a;
a.Set(2, 'b');
a.Set(3, 'c');
char* b;
a.Get(3, &b);
std::cout << b[0];
}
CopyNew argument _destiny should be T*& (as pointed out by WhozCraig in the comments). Otherwise, the function is changing the argument but not the variable passed to the function. In order to change the variable, you have to de-reference the argument, so its type has to be either a pointer or a reference to the variable type. Since the type of the variable is T*, the argument type should be T** or T*&

Process returned -1073741819 (0xC0000005) for template with double but not int

I tried to make a dynamic array that adds elements at the beginning of the array. It works just fine with int, but when i try double, it gives me the error Process returned -1073741819 (0xC0000005). Debugging it works perfectly and all are in range, but when i run it crashes.
This is the header:
#define DYNAMICARRAY_H
#include <cstddef>
template <class T>
class DynamicArray
{
public:
DynamicArray();
DynamicArray(size_t);
DynamicArray(const DynamicArray&);
virtual ~DynamicArray();
DynamicArray& operator=(const DynamicArray&);
T &operator[] (size_t);
void add(T element);
size_t getCapacity();
size_t getLength();
bool isEmpty();
void print();
void resizeArr();
protected:
private:
T *arr;
size_t capacity;
size_t length;
};
#endif // DYNAMICARRAY_H
This is the .cpp
#include "DynamicArray.h"
#include <iostream>
template <class T>
DynamicArray<T>::DynamicArray()
{
length = 0;
capacity = 1;
arr = (T*)malloc(capacity * sizeof(arr));
if(!arr){
throw std::bad_alloc();
}
}
template <class T>
DynamicArray<T>::DynamicArray(size_t newSize)
{
length = 0;
capacity = newSize;
arr = (T*)malloc(capacity * sizeof(arr));
if(!arr){
throw std::bad_alloc();
}
}
template <class T>
DynamicArray<T>::~DynamicArray()
{
delete[] arr;
delete arr;
delete &capacity;
delete &length;
}
template <class T>
DynamicArray<T>::DynamicArray(const DynamicArray& other)
{
length = other.length;
capacity = other.capacity;
arr = (T*)malloc(capacity * sizeof(arr));
if(!arr){
throw std::bad_alloc();
}
for(size_t i = 0; i < length; i++){
arr[i] = other.arr[i];
}
}
template <class T>
DynamicArray<T>& DynamicArray<T>::operator=(const DynamicArray& rhs)
{
if (this == &rhs){
return *this;
}
delete[] arr;
length = rhs.length;
capacity = rhs.capacity;
arr = (T*)malloc(capacity * sizeof(arr));
if(!arr){
throw std::bad_alloc();
}
for(size_t i = 0; i < length; i++){
arr[i] = rhs.arr[i];
}
return *this;
}
template <class T>
size_t DynamicArray<T>::getLength()
{
return length;
}
template <class T>
size_t DynamicArray<T>::getCapacity()
{
return capacity;
}
template <class T>
bool DynamicArray<T>::isEmpty(){
return length == 0;
}
template <class T>
T &DynamicArray<T>::operator[] (size_t index)
{
if(index >= length){
std::cout << "Array index out of bounds" << "\n";
exit(0);
}
return arr[index];
}
template <class T>
void DynamicArray<T>::add(T element)
{
if(length >= capacity){
resizeArr();
}
if(!isEmpty()){
for(size_t i = length; i > 0; i--){
arr[i] = arr[i-1];
}
}
arr[0] = element;
length ++;
}
template <class T>
void DynamicArray<T>::print()
{
if(length == 0){
std::cout << "The array is empty!";
}
else{
for(size_t i = 0; i < length; i++){
std::cout << arr[i] << " ";
}
}
std::cout << "\n";
}
template <class T>
void DynamicArray<T>::resizeArr(){
size_t newCapacity = capacity * 2;
T *arr2 = (T*)realloc(arr, newCapacity * sizeof(arr));
if(!arr2){
std::cout << "Bad memory allocation";
throw std::bad_alloc();
}
arr = arr2;
capacity = newCapacity;
}
template class DynamicArray<double>;
template class DynamicArray<int>;
And the main
#include "DynamicArray.h"
#include <cstdlib>
#include <time.h>
#include <cstddef>
using namespace std;
int main()
{
srand (time(NULL));
DynamicArray<int> d(5);
int randomInt;
for(size_t i = 0; i < d.getCapacity(); i++){
randomInt = rand()% 100;
d.add(randomInt);
}
d.print();
d.add(5);
d.add(55);
d.add(3);
d.add(33);
d.add(37);
d.print();
delete &d;
cout << "\n\n";
DynamicArray<double> d2(5);
double randomDouble;
for(size_t i = 0; i < d2.getCapacity() - 3; i++){
//randomDouble = (double)rand() / ((double)RAND_MAX);
randomDouble = 0.5f;
d2.add(randomDouble);
d2.print();
}
d2.print();
return 0;
}
It crashes at the second for in the main, I've tried to make sure everything it set correctly, but still won't work:
for(size_t i = 0; i < d2.getCapacity() - 3; i++){
//randomDouble = (double)rand() / ((double)RAND_MAX);
randomDouble = 0.5f;
d2.add(randomDouble);
d2.print();
}
arr = (T*)malloc(capacity * sizeof(arr));
delete[] arr;
delete arr;
delete &capacity;
delete &length;
delete &d;
You pass pointers to delete[] and delete that were not returned from new[] or new respectively. Behaviour of the program is undefined. Relevant language rule:
[expr.delete]
... In a single-object delete expression, the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject representing a base class of such an object. If not, the behavior is undefined. In an array delete expression, the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression.
If not, the behavior is undefined. ...
Every delete expression of your program violate this rule.
To fix this, you must consistently use free on memory allocated with malloc, realloc or strdup, and use delete with pointers allocated with new, delete[] with pointers allocated with new[], absolutely no deallocation functions with pointers to non-dynamic objects such as member variables or objects with automatic or static storage duration, (or invalid pointers).
arr = (T*)malloc(capacity * sizeof(arr));
sizeof(arr) is the same as sizeof(T*) which isn't what you want, I suppose.
This should rather be sizeof(*arr) or sizeof(T).
Apart from that, don't mix malloc/delete or new/free, as others already pointed out.
If you're doing C, use malloc/free, and if you're in C++ use new/delete.
Using new would change the above to
arr = new T[capacity];
avoiding the whole sizing altogether.

Minimal C++ STL Vector Implementation Problems

I have a technical problem and it's really confusing me. I apologise in advance because I may not be giving the relevant details; I don't yet why it's going wrong and it would be excessive to include all the code I'm working with.
I'm working with a large program that uses the C++ STL. I'm moving this code to a very sensitive environment without a standard clib nor STL implementaton; it will redefine malloc/free/new/delete etc... For that, I need to replace the std:: parts with my own simplified implementations. I've started with std::vector. Right now it's running in the standard ecosystem so it's the GNU libc and STL. The only thing that's changed is this vector class.
When I execute the program with the replaced class, it segfaults. I've put this through GDB and found that the program will request an object from the vector using the subscript operator. When the object reference is returned, a method is invoked and the program segfaults. It seems it can't find this method and ends up in main_arena() in GDB. The type of the object is an inherited class.
I'm really not sure at all what the problem is here. I would love to provide additional details, but I'm not sure what more I can give. I can only assume something is wrong with my vector implementation because nothing else in the program has been changed. Maybe there's something obvious that I'm doing wrong here that I'm not seeing at all.
I'm using: g++ (GCC) 4.4.5 20110214 (Red Hat 4.4.5-6)
I'd really appreciate any feedback/advice!
#ifndef _MYSTL_VECTOR_H_
#define _MYSTL_VECTOR_H_
#include <stdlib.h>
#include <assert.h>
typedef unsigned int uint;
namespace mystl
{
/******************
VECTOR
********************/
template <typename T>
class vector
{
private:
uint _size;
uint _reserved;
T *storage;
void init_vector(uint reserve)
{
if (reserve == 0)
{
_reserved = 0;
return;
}
storage = (T*)malloc(sizeof(T)*reserve);
assert(storage);
_reserved = reserve;
}
public:
vector()
{
// std::cerr << "default constructor " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
}
vector(const vector<T> &other)
{
// std::cerr << "copy constructor " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(other.size());
_size = other.size();
for (uint i=0; i<other.size(); i++)
{
storage[i] = T(other[i]);
}
}
vector(uint init_num, const T& init_value)
{
// std::cerr << "special constructor1 " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(init_num);
for (size_t i=0; i<init_num; i++)
{
push_back(init_value);
}
}
vector(uint init_num)
{
// std::cerr << "special constructor2 " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(init_num);
}
void reserve(uint new_size)
{
if (new_size > _reserved)
{
storage = (T*)realloc(storage, sizeof(T)*new_size);
assert(storage);
_reserved = new_size;
}
}
void push_back(const T &item)
{
if (_size >= _reserved)
{
if (_reserved == 0) _reserved=1;
reserve(_reserved*2);
}
storage[_size] = T(item);
_size++;
}
uint size() const
{
return _size;
}
~vector()
{
if (_reserved)
{
free(storage);
storage = NULL;
_reserved = 0;
_size = 0;
}
}
// this is for read only
const T& operator[] (unsigned i) const
{
// do bounds check...
if (i >= _size || i < 0)
{
assert(false);
}
return storage[i];
}
T& operator[] (unsigned i)
{
// do bounds check...
if (i >= _size || i < 0)
{
assert(false);
}
return storage[i];
}
// overload = operator
const vector<T>& operator= (const vector<T>& x)
{
// check for self
if (this != &x)
{
_reserved = 0;
_size = 0;
storage = NULL;
init_vector( x.size() );
for(uint i=0; i<x.size(); i++)
{
storage[i] = T(x[i]);
}
_size = x.size();
}
return *this;
}
uint begin() const
{
return 0;
}
void insert(uint pos, const T& value)
{
push_back(value);
if (size() == 1)
{
return;
}
for (size_t i=size()-2; i>=pos&& i>=0 ; i--)
{
storage[i+1] = storage[i];
}
storage[pos] = value;
}
void erase(uint erase_index)
{
if (erase_index >= _size)
{
return;
}
//scoot everyone down by one
for (uint i=erase_index; i<_size; i++)
{
storage[i] = storage[i+1];
}
_size--;
}
void erase(uint start, uint end)
{
if (start > end)
{
assert(false);
}
if (end > _size)
end = _size;
for (uint i=start; i<end; i++)
{
erase(start);
}
assert(false);
}
void clear()
{
erase(0,_size);
}
bool empty() const
{
return _size == 0;
}
}; //class vector
}
#endif // _MYSTL_VECTOR_H_
Wow!
Your assignment operator also leaks memory.
Becuause you are using malloc/release the constructor to your type T will will not be called and thus you can not use your vector for anything except the most trivial of objects.
Edit:
I am bit bored this morning: Try this
#include <stdlib.h> // For NULL
#include <new> // Because you need placement new
// Because you are avoiding std::
// An implementation of swap
template<typename T>
void swap(T& lhs,T& rhs)
{
T tmp = lhs;
lhs = rhs;
rhs = tmp;
}
template <typename T>
class vector
{
private:
unsigned int dataSize;
unsigned int reserved;
T* data;
public:
~vector()
{
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Because we use placement new we must explicitly destroy all members.
data[loop].~T();
}
free(data);
}
vector()
: dataSize(0)
, reserved(10)
, data(NULL)
{
reserve(reserved);
}
vector(const vector<T> &other)
: dataSize(0)
, reserved(other.dataSize)
, data(NULL)
{
reserve(reserved);
dataSize = reserved;
for(unsigned int loop;loop < dataSize;++loop)
{
// Because we are using malloc/free
// We need to use placement new to add items to the data
// This way they are constructed in place
new (&data[loop]) T(other.data[loop]);
}
}
vector(unsigned int init_num)
: dataSize(0)
, reserved(init_num)
, data(NULL)
{
reserve(reserved);
dataSize = reserved;
for(unsigned int loop;loop < dataSize;++loop)
{
// See above
new (&data[loop]) T();
}
}
const vector<T>& operator= (vector<T> x)
{
// use copy and swap idiom.
// Note the pass by value to initiate the copy
swap(dataSize, x.dataSize);
swap(reserved, x.rserved);
swap(data, x.data);
return *this;
}
void reserve(unsigned int new_size)
{
if (new_size < reserved)
{ return;
}
T* newData = (T*)malloc(sizeof(T) * new_size);
if (!newData)
{ throw int(2);
}
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Use placement new to copy the data
new (&newData[loop]) T(data[loop]);
}
swap(data, newData);
reserved = new_size;
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Call the destructor on old data before freeing the container.
// Remember we just did a swap.
newData[loop].~T();
}
free(newData);
}
void push_back(const T &item)
{
if (dataSize == reserved)
{
reserve(reserved * 2);
}
// Place the item in the container
new (&data[dataSize++]) T(item);
}
unsigned int size() const {return dataSize;}
bool empty() const {return dataSize == 0;}
// Operator[] should NOT check the value of i
// Add a method called at() that does check i
const T& operator[] (unsigned i) const {return data[i];}
T& operator[] (unsigned i) {return data[i];}
void insert(unsigned int pos, const T& value)
{
if (pos >= dataSize) { throw int(1);}
if (dataSize == reserved)
{
reserve(reserved * 2);
}
// Move the last item (which needs to be constructed correctly)
if (dataSize != 0)
{
new (&data[dataSize]) T(data[dataSize-1]);
}
for(unsigned int loop = dataSize - 1; loop > pos; --loop)
{
data[loop] = data[loop-1];
}
++dataSize;
// All items have been moved up.
// Put value in its place
data[pos] = value;
}
void clear() { erase(0, dataSize);}
void erase(unsigned int erase_index) { erase(erase_index,erase_index+1);}
void erase(unsigned int start, unsigned int end) /* end NOT inclusive so => [start, end) */
{
if (end > dataSize)
{ end = dataSize;
}
if (start > end)
{ start = end;
}
unsigned int dst = start;
unsigned int src = end;
for(;(src < dataSize) && (dst < end);++dst, ++src)
{
// Move Elements down;
data[dst] = data[src];
}
unsigned int count = start - end;
for(;count != 0; --count)
{
// Remove old Elements
--dataSize;
// Remember we need to manually call the destructor
data[dataSize].~T();
}
}
unsigned int begin() const {return 0;}
}; //class vector
With your current memory handling, this vector would only work with plain old data types.
To handle all types, it must ensure that objects
are actually created (malloc doesn't do that),
destroyed (free doesn't do that),
and you can't reallocate memory with realloc, because complex objects are not guaranteed to remain valid if they are byte-wise copied to another location.
Looks like the answer can be found in your question: "When the object reference is returned, a method is invoked and the program segfaults. It seems it can't find this method and ends up in main_arena() in GDB. The type of the object is an inherited class."
You probably store base class instance T in the vector, but make push_back for the instance of the class inherited from T. In push_back {storage[_size] = T(item);} you cast (actually make copy constructor T:T(const T&)) item to T (this probably named 'type cut'), then get reference to T and invoke a method of the class inherited from T using virtual table of T where the method is not defined yet/abstract. Am I right?
To make it properly work you should put T* in the vector or shared_ptr/unique_ptr depending on the ownership terms you apply to vector elements.
Generally in vector you can store only POD (Plain Old Data) types.

c++ array class problems

Alright, so without going into detail on why I'm writing this class, here it is.
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
aType * Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
aType * Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
aType * Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
It is supposed to be a std::Vector type object, without all the bells and whistles.
Problem is, it doesn't seem to work.
I basically start by going
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
I get an Access Violation Reading Location error and it hits on the line
Array[_Count] = Item
in the Push_back function.
The problem seems to be that it's not treating the Array object as an array in memory.
I've spent time going through the code step by step, and I don't know what else to say, it's not operating right. I don't know how to word it right. I'm just hoping someone will read my code and point out a stupid mistake I've made, because I'm sure that's all it amounts to.
Update
So now I changed 3 initializations of Array in nArray(), nArray(int Count), and Resize(int newSize)
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
This is how my code was before. Anyway, the original problem was the fact that when I try to access a specific element in the array, it just accesses the first element, and it doesn't seem to add elements eather. It doesn't seem to be treating Array as an array.
int Resize(int newSize)
{
.
.
aType * Array = new aType[newSize*2];
At this point, instead of updating the member variable as you intended, you've actually created a local variable called Array whose value is discarded when you exit from Resize(). Change the line to
Array = new aType[newSize*2];
The same thing is happening in your constructors, they also need changing accordingly. Moreover, since the default constructor allocates an array, you should set the size members accordingly. You have too many of these: an array needs to keep track of current element count and maximum capacity, however you appear to have three members. What is the purpose of the third? Redundant information is bad, it makes code difficult to read and without a single point of truth it is easier to make mistakes.
With the code in Resize(), you can do better: the second copy is completely redundant.
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
Also, in
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
you need curly braces around body of the if(), just indentation on its own won't do the trick:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
{
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
You have a number of problems. At a guess, the one causing problems so far is that your default ctor (nArray::nArray()) defines a local variable named Array that it initializes, which leaves nArray::Array uninitialized.
Though you probably haven't seen any symptoms from it (yet), you do have at least one more problem. Names starting with an underscore followed by a capital letter (such as your _Size, _MaxSize, and _Count) are reserved for the implementation -- i.e., you're not allowed to use them.
The logic in your Resize also looks needlessly inefficient (if not outright broken), though given the time maybe it's just my brain not working quite right at this hour of the morning.
Your array is not initialized by the constructors and resize function (working on local vars instead).
And is there a reason you want to store instances of string and not pointers to string (string *) ?
I think the answer after the changes is in moonshadow's reply:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
This code will always return aType(), the last two lines will never be reached.
You might also want to check what happens if you start out with a default-constructed nArray. (Hint: you call Resize(_MaxSize); but what is the value of _MaxSize in this case?
Edit:
This outputs "asdf2" for me as it should be (with the initialization and the braces fixed):
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1) {
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
#include <string>
#include <iostream>
using namespace std;
int main()
{
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
}