I've been getting this error for some time, and I have no clue how to fix it.
I searched for similar problem here on stack overflow, but I've failed to find anything.
Source code:
template <typename T>
class Dynamic_Array
{
private:
T* actual_array;
unsigned int number_of_elements;
public:
Dynamic_Array() {}
~Dynamic_Array() {delete[] actual_array;}
unsigned int get_size() const {return number_of_elements;}
T& operator [](unsigned int index) {return actual_array[index];}
void operator +=(T&);
void operator -=(unsigned int);
};
template <typename T> /*Not sure if this is needed, but compiler doesn't mind, still prints the same error*/
void Dynamic_Array<T>::operator+=(T& object)
{
if(number_of_elements>1)
{
T* temp_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
temp_array[i]=actual_array[i];
}
delete[] actual_array;
actual_array = new T[number_of_elements+1];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array=NULL;
actual_array[number_of_elements]=object;
number_of_elements++;
}
else
{
number_of_elements++;
actual_array = new T[1];
}
}
void Dynamic_Array<T>::operator-=(unsigned int index)
{
T* temp_array = new T[number_of_elements-1];
for(unsigned int i=0, j=0;i<number_of_elements;i++)
{
if(i!=index)
{
temp_array[j]=actual_array[i];
j++;
}
}
delete[] actual_array;
number_of_elements--;
actual_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array = NULL;
}
According to compiler, the error is present in line 18 (the empty one between "};" and "template"
As I said, I have no idea what I screwed up, so any help is appreciated.
When you define member functions outside of a class template declaration then you need to specify the template for each function. When you define
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
You need to have the template part as well like
template <typename T>
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
This has to be present for every function definition that you do out of line. A single template <typename T> at the start of all the definition does not apply to all of the function definitions.
Dynamic_Array is a template class so when defining operator+= and operator-= outside the scope of the class you need to provide template type as follows:
template<typename T> void Dynamic_Array<T>::operator+=(T& object) {
//...
}
template<typename T> void Dynamic_Array<T>::operator-=(unsigned int index) {
//...
}
Also, I should note that it is somewhat odd to have void as a return type for operator+= and operator-=, typically you should return a reference to the altered instance of this, i.e:
template<typename T> Dynamic_Array<T>& Dynamic_Array<T>::operator+=(const T& object) {
//...
}
Related
I'm sure this question is super simple, I'm just quite new to programming and to C++ in general.
For my class, we are making a Vector with a class template. My professor has supplied the .h file and we have to write the integrated .cpp file. Heres the .h file:
#ifndef SIMPLEVECTOR_H
#define SIMPLEVECTOR_H
#include <iostream>
#include <new> // Needed for bad-alloc exception
#include <cstdlib> // Needed for the exit function
using namespace std;
template <class T>
class SimpleVector
{
private:
T *aptr; // To point to the allocated array
int arraysize; // Number of elements in the array
void memError(); // Handles memory allocation errors
void subError(); // Handles subscripts out of range
public:
SimpleVector()
{
aptr = 0;
arraysize = 0;
}
SimpleVector(int s);
SimpleVector(const SimpleVector & sv);
~SimpleVector();
int size() const
{
return arraysize;
}
T getElementAt(int sub);
T &operator[](const int);
};
#endif //SIMPLEVECTOR_H
And here is my implementation:
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <class T>
SimpleVector<T>::SimpleVector(int s)
{
if(s<1)
{
arraysize=1;
}
else
{
arraysize=s;
}
try
{
aptr = new T [arraysize];
}
catch (bad_alloc)
{
memError();
}
for(int i=0;i<arraysize;i++)
{
aptr[i]=0;
}
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <class T>
void SimpleVector<T>::memError()
{
cout<<"Error: cannot allocate memory."<<endl;
exit(EXIT_FAILURE);
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <class T>
void SimpleVector<T>::memError()
{
cout<<"Error: cannot allocate memory."<<endl;
exit(EXIT_FAILURE);
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <class T>
T SimpleVector<T>::getElementAt(int sub)
{
return aptr[sub];
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <class T>
SimpleVector<T>::~SimpleVector()
{
delete aptr;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <class T>
void SimpleVector<T>::subError()
{
cout<<"Subscripts out of range."<<endl;
exit(EXIT_FAILURE);
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <class T>
SimpleVector<T>::SimpleVector(const SimpleVector & sv)
{
aptr=sv.aptr;
}
template <class T>
T<T>&::operator[](const int &)
{
return aptr[];
}
I know that my overload operator is way off and makes no sense, I just dont understand the syntax well enough to even know where to begin. Obvisouly, the operator should return the value of the aptr at whatever index was passed in through [].
There are multiple problems with your code, including:
Not catching bad_alloc correctly (never catch an exception class by value, always by reference).
duplicate definitions of memError(). You need to remove one of them.
~SimpleVector() using delete instead of delete[].
SimpleVector(const SimpleVector &) making a shallow copy of sv.aptr when it needs to make a deep copy instead.
getElementAt() not calling subError() if sub is out of range. Historically, operator[] doesn't perform range checking, but you can if you want/need to.
But, to answer the specific question you asked, your operator[] is implemented all wrong. Aside from the obvious syntax error in writing its definition, and that the definition does not match the declaration, internally it simply needs to do the same return action that the getElementAt() method is doing, eg:
template <class T>
T& SimpleVector<T>::operator[](const int sub)
{
return aptr[sub];
}
I tried to implement my own class named Array that act mostly like a vector because I don't want to use std. It works well with basic classes but when I want to instantiate an Array of a class that contains an Array (class Scene for exemple) it stops the program saying "Windows stoped fonctionning"... When I try to search for the error with break points I saw that it says "segmentation fault" when the program is at the destructor.
Here's my classes :
Array.h
#ifndef NAME_ARRAY_H
#define NAME_ARRAY_H
#include <stdexcept>
#include <iostream>
#include "malloc.h"
template <class T>
class Array {
private:
T *m_array;
unsigned int m_tot_size;
unsigned int m_actual_size;
public:
Array(unsigned int size);
Array(Array<T> const& paste);
bool add(T var);
const T& get(unsigned int index);
bool remove(unsigned int index);
void kill();
unsigned int getActualSize() const;
unsigned int getTotalSize() const;
T* getArray() const;
T& operator[](unsigned int index);
Array<T>& operator=(Array<T> const& paste);
~Array();
};
//CONSTRUCTOR
template <class T>
Array<T>::Array(unsigned int size) : m_tot_size(size), m_actual_size(0) {
m_array = (T*) malloc(size * sizeof(T));
}
template <class T>
Array<T>::Array(Array<T> const &paste) : m_tot_size(paste.m_tot_size),
m_actual_size(paste.m_actual_size) {
m_array = new T(*(paste.m_array));
}
//METHODES PUBLIC
template <class T>
const T & Array<T>::get(unsigned int index) {
if (index >= m_actual_size || index < 0)
throw std::out_of_range("Index out of range");
return m_array[index];
}
template <class T>
bool Array<T>::remove(unsigned int index) {
if(index < m_actual_size && m_actual_size != 0) {
m_actual_size--;
m_array[index] = m_array[m_actual_size];
return true;
}
return false;
}
template <class T>
bool Array<T>::add(T obj) {
if (m_actual_size >= m_tot_size) {
T *temp;
temp = (T*) realloc(m_array,5*sizeof(T));
m_array = temp;
m_array[m_actual_size] = obj;
m_actual_size++;
m_tot_size += 5;
return false;
} else {
m_array[m_actual_size] = obj;
m_actual_size++;
return true;
}
}
template <class T>
void Array<T>::kill() {
free(m_array);
delete [] m_array;
m_array = nullptr;
m_actual_size = 0;
m_tot_size = 0;
}
//ACCESSOR
template <class T>
unsigned int Array<T>::getActualSize() const { return m_actual_size; }
template <class T>
unsigned int Array<T>::getTotalSize() const { return m_tot_size; }
template <class T>
T* Array<T>::getArray() const { return m_array; }
//OPERATOR
template <class T>
T& Array<T>::operator[](unsigned int index) { return m_array[index]; }
template <class T>
Array<T>& Array<T>::operator=(Array<T> const& paste) {
if(this != &paste) {
m_tot_size = paste.m_tot_size;
m_actual_size = paste.m_actual_size;
free(m_array);
delete [] m_array;
m_array = nullptr;
m_array = new T(*(paste.m_array));
}
return *this;
}
//DESTRUCTOR
template <class T>
Array<T>::~Array() {
free(m_array);
delete [] m_array;
m_array = nullptr;
}
Scene.cpp :
#include "Scene.h"
Scene::Scene(std::string sceneName) : m_name(sceneName), m_array_position(20) {
}
void Scene::update() {}
void Scene::render() {}
Scene::~Scene() {
//m_array_position.kill();
//m_array_systems.kill();
}
Scene.h
#ifndef NAME_SCENE_H
#define NAME_SCENE_H
#include <string>
#include <unordered_map>
#include "../components/Position.h"
#include "../utils/Array.h"
#include "../systems/System.h"
class Scene {
private:
std::string m_name;
Array<Position> m_array_position;
public:
Scene(std::string sceneName);
void update();
void render();
~Scene();
};
main
Array<Scene> scenes(1);
I think the problem is that the program destroy the Array and then try to destroy the Array (Position is just a struct) but I'm not sure and I don't know what to do to correct it. Can someone please help me ?
I see in a lot of places code like this:
free(m_array);
delete [] m_array;
This doesn't look good to me. When allocating and deallocating memory, you have to match the allocation method with the deallocation:
If you reserve memory with "malloc", you free it with "free"
If you reserve with "new", you deallocate with "delete"
If you reserve with "new []", then you free with "delete []"
You should only use one of the methods or, if you REALLY need to mix them, then you should keep something tracking which method you would need to free the memory.
[Solved]: The problem was not in template class initialization, but with code-specific issue of using undefined macro inside a template class constructor. The compiler error did not complain about undefined symbol, but was (wrongfully) related to lambdas.
I've searched for an answer but couldn't find an exact one. The closest answer is here: C++ invoke explicit template constructor but I'm not sure if that is entirely related to my question.
And my question is, how can I initialize a member of structure B in initialization list if the member is a template class?
Header ClassA.h:
#ifndef _A_
#define _A_
#include <typeinfo>
#include <windows.h>
template<class Type> class A{
int u,v;
Type** pointer;
public:
A();
A(int number);
~A();
Type& operator[] (int i){
typeid(Type);
return *pointer[i];
}
Type& Get(int i)
{
typeid(Type);
return *pointer[i];
}
Type *GetPointer(int i)
{
typeid(Type);
return pointer[i];
}
Type* add ();
Type& add(Type *element);
Type& add(Type *element, int place);
void expand(int NewLength);
void swap(Type *element, int place);
void remove(int number);
void remove(Type *element);
void removePointer(int number);
void removePointer(Type *element);
};
template<class Type>A<Type>::A(){
u = 128;
v = 10;
}
template<class Type>A<Type>::A(int number){
//some thing to do with number;
u = number;
v = 10;
New( pointer, Type *[u] );
}
template <class Type> A<Type>::~A()
{
}
template <class Type> void A<Type>::expand(int NewLength)
{
Type **NewList = NULL;
NewList = new Type*[NewLength];
}
template <class Type> Type* A<Type>::add ()
{
pointer[u] = new Type;
}
template <class Type> Type& A<Type>::add(Type *element)
{
}
template <class Type> Type& A<Type>::add(Type *element, int place)
{
}
template <class Type> void A<Type>::swap(Type *element, int place)
{
}
template <class Type> void A<Type>::remove(Type *element)
{
}
template <class Type> void A<Type>::removePointer(int nume)
{
}
template <class Type> void A<Type>::removePointer(Type *element)
{
}
#endif
Header StructB.h:
#pragma once
#ifndef _B_
#define _B_
#include "ClassA.h"
struct C{
float x,y,z;
};
struct B{
private:
B(){
}
public:
int x,y;
A<B*> member1;
A<C> member2;
B(int X,int Y) : member1(5),member2(5) {
//initialize x,y
}
void Add(B* otherB){
B** _pOtherB = new B*; (*_pOtherB) = otherB;
member1.add(_pOtherB);
}
};
#endif
The compiler complains with this error (and some other errors, I can post them if nedded):
error C3493: 'number' cannot be implicitly captured because no default capture mode has been specified
Is there any way to do this, or some workaround perhaps?
Thanks in advance :D
Either the code you've given us isn't complete, or it is broken. This line:
New(pointer, Type *[u]);
seems to be referencing either some missing member method or global function, or it is simply invalid. The error message is kinda cryptic, but that's C++ for you.
I'm going to assume that New is some kind of macro, because no normal function (even a templated one) can take this sort of type definition as a parameter. You've not given us the definition of New, so there's no way we can tell. It is probably the absense of this macro (maybe a wrapper for some sort of memory debugging system?) that is causing the crazy error.
If I replace the New line with this:
pointer = new Type*[u];
the code compiles fine.
I am trying to pass a function pointer in to a constructor of a class. However, when I try to compile the code, I am getting an error. The code and error are :
quickfind.h
#ifndef QUICKFIND_H
#define QUICKFIND_H
#endif // QUICKFIND_H
template <class T>
class QuickFind
{
private:
int size;
int *array;
int (*giveIndex)(const void *a);
public:
QuickFind<T>(int n,int (*ptr)(const void *));
void connect (const T* u,const T* v);
bool isConnected(const T* u,const T* v);
};
Constructor definition in file quickfind.cpp
template <class T>
QuickFind<T>::QuickFind(int n,int (*ptr)(const void *))
{
size=n;
array=new int[n];
giveIndex=ptr;
for(int i=0;i<n;i++)
{
array[i]=i;
}
}
In my main function file :
int giveIndex (const void *ptr)
{
temp *tptr=(temp*)ptr;
return tptr->getA();
}
int main()
{
QuickFind<temp> *qf=new QuickFind<temp>(10,giveIndex);
}
Here, I am getting 'undefined reference to QuickFind<temp>::QuickFind(int, int (*)(void const*))' error. I am not able to figure out the problem...please help.
One thing wrong, you don't need the on the constructor:
template <class T>
class QuickFind
{
private:
int size;
int *array;
int (*giveIndex)(const void *a);
public:
QuickFind(int n,int (*ptr)(const void *)); /// <---- here, no <T>
void connect (const T* u,const T* v);
bool isConnected(const T* u,const T* v);
};
In your case, the class it templated, but this function isn't. And, template functions must be defined in the header file so that the file that includes them can see the code and substitute the parameter types.
Put all of the following in one CPP file to see it work. As noted in other comments you must, for templated classes, put the entire definition in the header file. Do not separate the function declaration from its definitions into a separate CPP file. In this case having the entire implementation in the one CPP file serves the same purpose.
I have made some changes to your code to make it typesafe, memory leak safe and more exception safe. For example I replaced your dynamically allocated array with std::vector. std::vector has all the features you need but manages the memory for you and will be cleaned up when your class goes out of scope.
#include <vector>
#include <iostream>
#include <functional>
template <typename T>
class QuickFind
{
private:
std::vector<int> data;
std::function<int (const T&)> func;
public:
QuickFind(int n, std::function<int (const T&)> f) : data(n), func(f)
{
int i = 0;
for(auto it = data.begin(); it != data.end(); ++it)
data[i]=i++;
}
void connect (const T& u, const T& v)
{
std::cout << func(u) << "\n";
std::cout << func(v) << "\n";
}
bool isConnected(const T* u,const T* v);
};
class temp
{
int val;
public:
temp(int i) : val(i)
{}
int getA() const
{
return val;
}
};
int giveIndex (const temp &t)
{
return t.getA();
}
int main()
{
temp t1(5), t2(10);
QuickFind<temp> qf1(10,giveIndex);
qf1.connect(t1, t2);
// this example uses a lambda as the callback
auto giveIndex2 = [](const temp& t) { return t.getA(); };
QuickFind<temp> qf2(20, giveIndex2);
qf2.connect(t1, t2);
}
The compiler wants to know objects of which types will be instantiated from a template class at the time of compilation of template class methods. So, there may arise compile-time or link-time errors.
This explains more about various errors and their causes.
Adding #include "quickfind.cpp" in the end of the header file worked in my case after some efforts.
I have a templated class, myFoo, which stores "stuff" of type T which can be either primitive or pointers to complex types. When myFoo is deleted, I want to release all the memory associated with everything it happens to be storing. This means I need to call delete on every pointer being stored but I might also end up calling delete on a primitive. Is this safe??
I've included a sketch of myFoo below to better highlight what's going on. I'm not sure if the behaviour of the destructor is well defined.
template<class T>
class myFoo
{
public:
myFoo(int size)
{
size_ = size;
T* foo = new T[size_];
}
void addFoo(T tmp, int index)
{
foo[index] = tmp;
}
virtual ~myFoo()
{
for(int i=0; i < size_; i++)
{
delete foo[i];
}
delete [] foo;
}
private:
int size_;
T* foo;
}
The only thing you can call delete on is a pointer type. It's an error to call delete on an int, for example. If you arrange your templates so that your code tries to do something that is an error, the compiler will let you know and refuse to compile your code.
So no, you don't have to worry about "accidentally" deleting a non-pointer.
Template specialization
template <class T> struct delete_it;
template <class T> struct delete_it<T*>
{
static void func(T* ptr) { delete ptr; }
};
template <> struct delete_it<int>
{
static void func(int) {}
};
template <> struct delete_it<double>
{
static void func(double) {}
};
Repeat for all primitive types. Then
virtual ~myFoo()
{
for(int i=0; i < size_; i++)
{
delete_it<T>::func(foo[i]);
}
delete [] foo;
}
Unchecked code.