C++ Template object composition - How to initialize correctly?

Pages: 12
I set my element2 to const Tree<T> * and set SetLastPosUsed to work with const.

I can't step inside my constructor, it just crashes on the definition of the method.


I'm getting sick with this :/
Yeah, me too

maybe you should just save the current code and rewrite both classes from the bottom up.
You allready learned a lot about const correctness i think, you should put that to use :)
SBAM! my problem occurs whenever i want to create an object who is composed by a list of objects of the same type!!


for example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <class T> class MyObject{

	public:
		..
		..
		
		MyObject(){}
		MyObject(const MyObject&){

			...
		}
	private:

		List<MyObject<T> > MyList
};



it crashes on the constructor without letting me to step inside, exactly the same of the trees.

Where am i making mistakes???

look this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
	#include "ListHeader.h"

	template <class T> class Queue{
		
		
		public:
			
			Queue(int NElems=0,T Value=T());
			
			Queue(const Queue<T>& Q2Copy){
				
				while (GetNElems()>Q2Copy.GetNElems()){
						
					Q.DeleteElement((ListNode<Queue<T> >*)(Q(LIST_END).NodePtr));	
				}
				
				while (GetNElems()<Q2Copy.GetNElems()){
					
					AddItem();
				}
			}
			~Queue(){}
			
			T &First();
			T &Last();
			
			void AddItem(T Value=T());
			
			int GetNElems() const;
			
		private:
		
			List<Queue<int> > Q;	
	};
	
#endif 


i know it's strange to have a list of queues in a queue object, but let's take it for good.


IT CRASHES. AND I ONLY WRITE THIS IN THE MAIN:

Queue<List<int> > Q1;


BUT, if i use List<T> Q in my private section, and declare a: List<Queue<int> > in the main, NO ERROR OCCURS and everything works fine.

AND STILL no problem occurs if my private section is of this type: List<List<T> > Q

i'm missing something.... can you please help me? :'(
Last edited on
Usually it is your job to find out where it crashes
put a std::cout << [method_name] << std::endl; in each function, so you see where the problem occures

edit:
You know what, I'm getting tired of this.
Can you give me all code related to the Problem?
Tree<T>
List<T>
ListNode<T>
ListCache??
maybe some more?
Last edited on
Everything got uploaded here:
http://www26.zippyshare.com/v/q4vMXbQM/file.html


i'm really sorry for the disturb gamer, i just would like this to get finished as soon as possible.


Okey, first of you should make your Filenames shorter

Usually you have a *.h or *.hpp file that you include.
Then you have a *.tpp (for template methods) that you include from your *.hpp file

Furthermore, your code is hard to read, I had a hard time figuring out where the Methods are in your implementation files.

So, now to the Problem.
I removed unnecessary Lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Tree
template <class T> 
class Tree
public:
    Tree(Tree<T> *MyFather=NULL) : Nodes() // calls default constructor of List<Tree<int>>
    { ... }
private:
    List< Tree<T> > Nodes;
};

// List
template <class T> 
class List
{		
public:
    List(int Elems=0, T Value2Assign=T()) // calls default constructor of Tree<int>
    { ... }
};


So when calling Tree<int> tree; you call the default constructor of tree which calls the default constructor of List which creates the Default constructor of Tree and so on, which results in an infinite loop and the Programm crashes.

You could resolve it with just making a normal default constructor and removing the default parameters of the current default constructor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class T> 
class List
{		
public:
    List() : ListCache(*this){

        //printf ("Costruttore Lista Chiamato.\n\n");
        Closing=false;
        NElems=0;
        SetFirstElement(NULL);
        SetLastElement(NULL);
    }

    List(int Elems, T Value2Assign)
    {  }
};
Last edited on
wow! really thank you gamer, you solved my problem!

But please, can you help me to understand this?

I understood that my old List constructor created an infinite loop, but what if i use it with this prototype?


List(int Elems=0)...

why shouldn't i make it the default one?

i tried this, and noticed that my Nodes list starts with one element, instead of zero elements...


can you explain this to me? Thank you really :)


but what if i use it with this prototype?


List(int Elems=0) { ... }

why shouldn't i make it the default one?

It shouldn't be a problem at all.
You can make it if you want.

i tried this, and noticed that my Nodes list starts with one element, instead of zero elements...

How did you implement it?

can you explain this to me?

I can try

Thank you really :)

You're welcome :)
Let's start from the beginning:

we had this constructor as the default one:

1
2
3
4
5
6
7
8
9
10
11
12
13
template <class T> List<T>::List(int NElems,T Value2Assign) : ListCache(*this){
		
		Closing=false;
		NElems=0;
		SetFirstElement(NULL);
		SetLastElement(NULL);

		if (NElems>0){
			
			AddElement(LIST_START,1,Value2Assign);
			AddElement(LIST_END,NElems-1,Value2Assign);	
		}
	}


But when the compilers allocates this method allocates, going in an infinite loop, list and tree constructor.

So, let's say i want to make this constructor the default one, FIRST i should take off my Value2Assign parameter, for the reason i just wrote (i hope i'm not wrong).


now, this is my new constructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
	template <class T> List<T>::List(int NElems) : ListCache(*this){
		
		Closing=false;
		NElems=0;
		SetFirstElement(NULL);
		SetLastElement(NULL);

		if (NElems>0){
			
			AddElement(LIST_START,1,0);
			AddElement(LIST_END,NElems-1,0);	
		}
	}


what happens here is that if i write in the main just this:

1
2
3
4
5
6
int main() {
	
	Tree<int> MyTree;
	
        return 0;
}


when calling my list destructor it goes in an endless loop, because deleteElement receives a NULL pointer... it's hard to explain here :/ you should try to check it with the code i sent you... may you?

Thanks :)

Let's start from the beginning:


we had my old constructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
template <class T> List<T>::List(int NElems, T Value2Assign) : ListCache(*this){
		
		Closing=false;
		NElems=0;
		SetFirstElement(NULL);
		SetLastElement(NULL);

		if (NElems>0){
			
			AddElement(LIST_START,1,Value2Assign);
			AddElement(LIST_END,NElems-1,Value2Assign);	
		}
	}



this wasn't good because when allocating memory for this method my compiler creates, in an endless loop, instances of Lists and trees.

am i wrong?


So now we have to take off Value2Assign parameter, obtaining this, leaving NElems=0 the default parameter:

1
2
3
4
5
6
7
8
9
10
11
12
13
template <class T> List<T>::List(int NElems) : ListCache(*this){
		
		Closing=false;
		NElems=0;
		SetFirstElement(NULL);
		SetLastElement(NULL);

		if (NElems>0){
			
			AddElement(LIST_START,1,0);
			AddElement(LIST_END,NElems-1,0);	
		}
	}


now, if in my main function i write this:

1
2
3
4
5
int main() {
	
	Tree<int> MyTree;
	return 0;
}



After the declaration my Nodes appears to have NElems=1 (debugging and observing Nodes Status)

which causes an endless loop in the destructor of my Nodes List, because FirstElement and LastElement are NULL and DeleteElement, which deletes actually a ListNode starting from his pointer, returns a printf saying that didn't do anything because the address received is NULL.


I think you could understand better what i'm saying if you try to debug and set the constructor as i did, may you? Thank you :)
Well, shouldn't you check in your IsEmpty method if the List is Empty?
If the List is Empty there is nothing to delete so it doesn't go in the loop.

In ~List, you call DeletElement.
When the last Element is deleted, you set the first and the last element to null, after that you delete FirstElement and LastElement (which are nullptr)


Also, it is not possible to convert 0 to all Types so you should change these lines of code:
1
2
3
4
5
6
7
8
9
10
11
12
13
template <class T> List<T>::List(int NElems) : ListCache(*this){
		
		Closing=false;
		NElems=0;
		SetFirstElement(NULL);
		SetLastElement(NULL);

		if (NElems>0){
			T temp;
			AddElement(LIST_START,1,temp); // temp instead of 0
			AddElement(LIST_END,NElems-1,temp);	 // temp instead of 0
		}
	}
Last edited on
The problem is that my list is not empty, NElems (the value that IsEmpty checks to say if Nodes is empty or not) is 1 and not 0, but i don't know where it gets incremented.

1
2
3
4
template <class T> bool List<T>::IsEmpty() const {
		
		return (LastElement==NULL && NElems==0);
	}


will not return true... and debugging i can't see no istruction which increments NElems...

So weird :/

EDIT: the problem doesn't appear with constructor List() set as the default constructor...

REEDIT:

Please note, Constructor List<T>::List(int NElems=0) : ListCache(*this) does exactly the same of List<T>::List() : ListCache(*this);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
	template <class T> List<T>::List() : ListCache(*this){
		
		Closing=false;
		NElems=0;
		SetFirstElement(NULL);
		SetLastElement(NULL);
	}
	
	template <class T> List<T>::List(int NElems) : ListCache(*this){
		
		Closing=false;
		NElems=0;
		SetFirstElement(NULL);
		SetLastElement(NULL);

		/*if (NElems>0){
			T Temp;
			AddElement(LIST_START,1,Temp);
			AddElement(LIST_END,NElems-1,Temp);	
		}*/
	}


I call it through this:

 
Tree(Tree<T>*MyFather=NULL):MyFather(MyFather),LastPosUsed(POS_UNDEFINED),Value(T()),Nodes(0){}	
Last edited on
Well, I'm stupid, it is quite obvious
In my Example, NElems is the NElems of the Object because there is no local NElems
In your Example you have a variable called NElems, so it changed that one
this->NElems is not initialized so ... yeah, it might be over 9000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <class T> List<T>::List(int NElems) : ListCache(*this){
		
		Closing=false;
		// NElems = 0; // sets the parameter NElems to 0, not this->NElems
		this->NElems=NElems;
                SetFirstElement(NULL);
		SetLastElement(NULL);

		if (NElems>0){
			T Temp;
			AddElement(LIST_START,1,Temp);
			AddElement(LIST_END,NElems-1,Temp);	
		}
	}
	


Last edited on
AAAAAND THAT'S IT MY MATE! WE MADE IT!


So let's resume:


My Tree declares a List of Tree:

List<Tree<int> Nodes

nodes has a constructor like this:


Nodes(int N=0,Value2Assign=T())


NOW...BECAUSE OF T= Tree<int>

My Nodes constructor starts an endless loop, so the ONLY way to avoid this is to delete Value2Assign parameter so that no loop gets started.


the only problem is that if i create a list of n elems, this elements cannot have a value chosen by me. but that's not a problem.

for what concerns trees, for example, if i create Nodes(30), i want that each element of my list (a tree) sets his father to the object who contains the List.

I can make this in the constructor, making Setfather method private and setting, after their allocation, for each element the respective father:

1
2
3
4
5
6
7
8
9
10
11
12
Tree(Tree<T> *MyFather=NULL): MyFather(MyFather),LastPosUsed(POS_UNDEFINED),Value(T()){
				
				int Counter;
				
				if (GetNElems()>0){
					
					for (Counter=0;Counter<GetNElems();Counter++){
						
						Nodes[Counter].SetFather(*this);	
					}
				}
			}	



BY THE WAY, FINALLY, WE CAN SAY THAT THIS THREAD HAS BEEN SOLVED! THANKS THANKS THANKS!

one negative note (if it has to be considered in this way) is that i had to use const_cast somewhere for "this" pointer and other things... but i think it would not be a problem because my object can't be modified by anything... am i wrong?


this may be the last posts my friend, so let's be happy! I owe you a beer!

GoodNight!
AAAAAND THAT'S IT MY MATE! WE MADE IT!

Good to hear :D

the only problem is that if i create a list of n elems, this elements cannot have a value chosen by me. but that's not a problem.

Sure, you can! ;)
List<Tree<int>> list(2, Tree<int>(5));

one negative note (if it has to be considered in this way) is that i had to use const_cast somewhere for "this" pointer and other things... but i think it would not be a problem because my object can't be modified by anything... am i wrong?

I still see no need for this, we can solve this problem too if you want?
It is not a problem but well... if you want to write maintainable code, you have to avoid that at all cost, or you have to document why exactly THERE WAS NO OTHER WAY to do it, because casting a const away means that you will change the object in a way but at the same time you gurantee with the const reference that the object's state won't change...


this may be the last posts my friend, so let's be happy! I owe you a beer!

Nah, proud anti-alcoholic 19 year old boy sitting here, but thanks for the offer ;)

Good Night! :D
Last edited on
It would be great!!! However i mark this as solved, maybe we can talk privately, would you?

Thanks!
Topic archived. No new replies allowed.
Pages: 12