Objekt parametrem metody – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Objekt parametrem metody – C / C++ – Fórum – Programujte.comObjekt parametrem metody – C / C++ – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené.
marpit0
Stálý člen
13. 3. 2013   #1
-
0
-

Zdravím, poprosil bych o menší radu.

Mám napsanou třídu pro seznam, kde mám metodu na vložení prvku do seznamu:

template <class T> void List1<T>::insert(const T value)
{
	item *newItem = new item;

	newItem->value = value;
	newItem->next = head;
	head = newItem;
}

Vše je v pořádku, když jsou do seznamu vkládány primitivní datové typy či objektové typy bez parametrického konstruktoru. Teď se dostávám k tomu, kde je problém. Do seznamu chci jako položku vkládat zásobník, který má v konstruktoru dva parametry - velikost (je realizován polem) a index, respektive pořadí, ve kterém zásobník vzniknul. Provedu tedy instanci třídy:

Stack1<int> s(size, index);

Vytvářím tedy zásobník datového typu int o velikosti size s indexem index. 

Nyní provedu operaci přidání do seznamu: 

l.insert(s);

Výsledkem je chyba kompilace: 

Error	1	error C2512: 'List1<T>::item' : no appropriate default constructor available	

Řešením by bylo vytvořit bezparametrický konstruktor zásobníku a inicializaci řešit pomocí metody, avšak k tomuto řešení se mi moc nechce přejít - takhle v konstruktoru mám jistotu, že inicializace proběhne vždy, kdybych to řešil bezparametrickým konstruktorem, tak bych musel i řešit stav, kdy by docházelo k práci s neinicializovaným zásobníkem. Navíc jsem to kdysi zkoušel pomocí metody a docházelo k problémům s uvolněním paměti v destruktoru (uvolnění vícekrát stejného bloku, dle hlášky VS). 

Existuje tedy řešení, jak zachovat parametrický konstruktor a tento objekt předávat do metody? Vždy jsem si myslel, že problémy parametrických konstruktorů jsou u polí, zde by mě možný problém nenapadl, inu, člověk se pořád učí.

Díky za rady a přeji hezký večer.

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
vitamin+8
Grafoman
13. 3. 2013   #2
-
0
-

#2
Ten zasobnik tam musis prekopirovat, cize potrebujes kopirovaci konstruktor a funkcia insert bude prebereat referenciu:

template <class T> 
void List1<T>::insert(const T& value)	// <-- referencia
{
	item *newItem = new item;

	newItem->value = value;		// <- tu sa zavola kopirovaci konstruktor
       //edit: nezavola, zavola sa operator=, moja chyba
	newItem->next = head;
	head = newItem;
}

struct X{
	X(const X& x){	//kopirovaci konstruktor
		//...
	}
	
};

Ak chces do listu vlozit novy prvok bez volania kopirovacieho konstruktoru tak budes musiet pouzit Variadic templates z c++11:

template <class T>
template <class... Params> 
void List1<T>::insert_new(Params... params){
	item *newItem = new item(params...);	// treba prerobit aj triedu item 
	//...
}

alebo pouzit std::list  :)

Nahlásit jako SPAM
IP: 95.105.157.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
marpit0
Stálý člen
13. 3. 2013   #3
-
0
-

#2 vitamin
proč to musí být předáváno jako reference?

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
vitamin+8
Grafoman
13. 3. 2013   #4
-
0
-

#3 marpit
Aby sa nevytvarala kopia.

Nahlásit jako SPAM
IP: 95.105.157.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
KIIV
~ Moderátor
+43
God of flame
13. 3. 2013   #5
-
0
-

#3 marpit
jinak se ti to bude kopirovat jeste i pri predavani do metody... nez se dostanes k ulozeni do struktury, tak budes mit nekolikatou kopii

Nahlásit jako SPAM
IP: 94.112.35.–
Program vždy dělá to co naprogramujete, ne to co chcete...
marpit0
Stálý člen
13. 3. 2013   #6
-
0
-

takže zásobník teďka vypadá takto:

konstruktor:

template <class T> Stack1<T>::Stack1(int size, int index)
{
	sp = 0;
	this->size = size;
	this->index = index;
	arr = new T[size];
}

a kopírovací konstruktor:

template <class T> Stack1<T>::Stack1(const Stack1 &s)
{
	this->sp = s.sp;
	this->size = s.size;
	this->index = index;
	this->arr = s.arr;
}

Doufám, že jsem to pochopil dobře.

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
marpit0
Stálý člen
13. 3. 2013   #7
-
0
-

#5 KIIV
Takže čistě teoreticky by bylo lepší třeba i při vyhledávání předávat objekt jako referenci? 

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
marpit0
Stálý člen
13. 3. 2013   #8
-
0
-

#2 vitamin
Aha, takže teda přetížit operátor = ?

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
vitamin+8
Grafoman
13. 3. 2013   #9
-
0
-

#8 marpit
Riesit sa to da takto:


template<class T>
class List{
		struct Item{
			T data;
			
			Item(const T& data):data(data){}
		
			template <class... P>	
			Item(P... p):data(p...){}	//<-- treba c++11
		};
	
	public:
		void insert(const T& data){
			Item* item = new Item(data);
			
			//...
		}
		
		template <class... P>
		void insert_new(P... p){		//<-- treba c++11
			Item* item = new Item(p...);
			
		}
	//...
	
};

struct X{
	X(int, long, double){}
	X(const X& x){}
};
int main(){
	X x(1, 2, 3.14);
	List<X> list;
	
	list.insert(x);	//zavola sa kopirovaci konstruktor
	
	list.insert_new(4, 5, 6.28);	//zavola sa konstruktor s 3 parametrami  (treba c++11)
	
}
Nahlásit jako SPAM
IP: 95.105.157.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
marpit0
Stálý člen
13. 3. 2013   #10
-
0
-

#9 vitamin
tak to už jde mimo mé znalosti

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
Martin Kozibrátka0
Stálý člen
13. 3. 2013   #11
-
0
-

Tvé nedostatky pramení z toho, že nevíš jak se u objektů používají kopírovací konstruktory a přiřazovací operátory

Nahlásit jako SPAM
IP: 88.83.169.–
Savana.cz - neomezený webhosting za pár kaček :)
vitamin+8
Grafoman
13. 3. 2013   #12
-
0
-

#10 marpit
Tak nez sa to naucis, tak mozes pouzit std::list:

#include <list>

struct X{
	X(int, long, double){}
	X(const X& x){}
};

int main(){
	std::list<X> list;

	list.push_back(X(1, 2, 3.3));
	list.push_back(X(4, 5, 6.3));
	list.push_back(X(7, 8, 9.3)); 
	list.emplace_back(10, 11, 12.0);	//treba c++11


}
Nahlásit jako SPAM
IP: 95.105.157.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
marpit0
Stálý člen
13. 3. 2013   #13
-
0
-

Takže žádný triviální způsob tedy neexistuje? Bezva, to abych se už pustil do přepisování. Jsem si to chtěl udělat univerzální a hold se to jaksi vymklo. 

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
Martin Kozibrátka0
Stálý člen
13. 3. 2013   #14
-
0
-

Předělávat nic nemusíš, jen si tam přidej kopírovací kontruktor a přetěž operátor přiřazení

Nahlásit jako SPAM
IP: 88.83.169.–
Savana.cz - neomezený webhosting za pár kaček :)
marpit0
Stálý člen
13. 3. 2013   #15
-
0
-

#14 Martin Kozibrátka
Přesně to jsem zkoušel a výsledek stejný (chybová hláška zmíněna výše). 

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
vitamin+8
Grafoman
13. 3. 2013   #16
-
0
-

#15 marpit
Postnie sem cely kod, povieme ti kde mas chybu

Nahlásit jako SPAM
IP: 95.105.157.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
marpit0
Stálý člen
13. 3. 2013   #17
-
0
-

list1.h

#ifndef _LIST1__
#define _LIST1__

template <class T> struct List1
{
private:
	struct item
	{
		T value;
		item *next;
	};

	item *current;
	item *head;

public:
	List1();
	~List1();

	void insert(const T);
	T get();
	void erase(const T);
	void clear();
		
	inline void reset()
	{
		current = head;
	}

	inline bool isEnd()
	{
		return (current == nullptr);
	}

	inline void isEmpty()
	{
		return (head == nullptr);
	}
};

#include "List1.hxx"

#endif

list1.hxx

template <class T> List1<T>::List1()
{
	head = nullptr;
	current = nullptr;
}

template <class T> List1<T>::~List1()
{
	clear();
}

template <class T> void List1<T>::insert(const T value)
{
	item *newItem = new item;

	newItem->value = value;
	newItem->next = head;
	head = newItem;
}

template <class T> T List1<T>::get()
{
	T tmp;

	tmp = current->value;
	current = current->next;

	return tmp;
}
		
template <class T> void List1<T>::erase(const T value)
{
	item *tmp = head;
	item *tmp2 = head;

	if (tmp == nullptr)
		return;

	if (tmp->value == value)
	{
		head = tmp->next;
		delete tmp;
			
		return;
	}

	tmp2 = tmp->next;

	while(tmp2 != nullptr)
	{
		if (tmp2->value == value)
		{
			tmp->next = tmp2->next;
			delete tmp2;

			return;
		}

		tmp = tmp2;
		tmp2 = tmp->next;
	}
}
	
template <class T> void List1<T>::clear()
{	
	while(head != nullptr)
	{
		item *tmp = head;
		head = head->next;
		delete tmp;
	}

	current = nullptr;
}

stack1.h

#ifndef _STACK1__
#define _STACK1__

template <class T> struct Stack1
{
private:
	T *arr;
	int size;
	int index;
	int sp;

public:
	Stack1(int, int);
	~Stack1();

	//provizorně

	Stack1(const Stack1 &s)
	{
		this->sp = s.sp;
		this->size = s.size;
		this->index = index;
		this->arr = s.arr;
	}

	//

	void Push(const T);
	T Pop();

	inline bool isEmpty()
	{
		return (sp == 0);
	}

	inline bool isFull()
	{
		return (sp >= size);
	}
	
	inline void clear()
	{
		sp = 0;
	}
};

#include "Stack1.hxx"

#endif

stack1.hxx

template <class T> Stack1<T>::Stack1(int size, int index)
{
	sp = 0;
	this->size = size;
	this->index = index;
	arr = new T[size];
}

template <class T> Stack1<T>::~Stack1()
{
	delete[] arr;
}

template <class T> void Stack1<T>::Push(const T value)
{
	arr[sp] = value;
	sp++;
}

template <class T> T Stack1<T>::Pop()
{
	sp--;
	return arr[sp];
}

main.cpp

#include <iostream>

#include "h\List1.h"
#include "h\Stack1.h"
#include "h\Constant.h"

typedef char* Exception;

using namespace std;

void createTrain(Stack1<int> &, const int);
void arrangeTrain(Stack1<int> &, List1<Stack1<int>> &, const int);
void rearrangeTrain(Stack1<int> &, List1<Stack1<int>> &, const int);

int main(int argc, char *args[])
{
	Stack1<int> train(M, 0);
	List1<Stack1<int>> station;

	createTrain(train, M);
	arrangeTrain(train, station, N);
	//rearrangeTrain(train, station, M);

	system("pause");
	return 0;
}

void createTrain(Stack1<int> &train, const int lenght)
{
	for (int i = 1; i <= lenght; i++)
	{
		train.Push(i);
		cout << "G" << i << " ";
	}

	cout << endl;
}

void arrangeTrain(Stack1<int> &train, List1<Stack1<int>> &station, const int track_lenght)
{
	static int index = 1;
	Stack1<int> track(track_lenght, index);

	while(!train.isEmpty())
	{
		int car = train.Pop();
		track.Push(car);

		cout << "O" << car << "[K" << index << "] ";
		
		if (track.isFull())
		{
			station.insert(track);
			index++;

			arrangeTrain(train, station, track_lenght);
		}
	}

	station.insert(track);
}	
	

Díky

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
KIIV
~ Moderátor
+43
God of flame
13. 3. 2013   #18
-
0
-

#15 + #17 marpit
std::list samozrejme taky potrebuje kopirovaci konstruktor a assignment operator... a ted nove se hodi i move konstuktor a assignment move operator (podle nove specky c++)

Nahlásit jako SPAM
IP: 94.112.35.–
Program vždy dělá to co naprogramujete, ne to co chcete...
Martin Kozibrátka0
Stálý člen
13. 3. 2013   #19
-
0
-

Do stack1.h si přidej bezparametrický konstruktor...

Nahlásit jako SPAM
IP: 88.83.169.–
Savana.cz - neomezený webhosting za pár kaček :)
marpit0
Stálý člen
13. 3. 2013   #20
-
0
-

#19 Martin Kozibrátka
Doplněno, kompilace OK, při běhu programu (na konci) dochází k vyvolání Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse).

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
Martin Kozibrátka0
Stálý člen
13. 3. 2013   #21
-
0
-

Problém je s 

template <class T> Stack1<T>::~Stack1()
{
delete[] arr;
}

a možná ještě někde jinde. Takže si projdi všechny místa kde něco dealokuješ. Měj na paměti, že automatické objekty také spustí svůj destruktor, když přestanou existovat, což může být jeden z tvých problémů...Tedy několikanásobné aplikování delete na jeden pointer

Nahlásit jako SPAM
IP: 88.83.169.–
Savana.cz - neomezený webhosting za pár kaček :)
marpit0
Stálý člen
13. 3. 2013   #22
-
0
-

#21 Martin Kozibrátka
tuž to je ostuda, koukám na to a nevšimnu si toho, díky za upozornění

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
vitamin+8
Grafoman
13. 3. 2013   #23
-
0
-

#22 marpit
 

template <class T> struct List1
{
private:
	struct item
	{
		T value;
		item *next;
		
		item(const T& v):
			value(v), 	//typ T musi mat kopirovaci konstruktor
			next(nullptr){}	
	};

	item *current = nullptr;	//atributy sa daju inicializovat aj takto
	item *head = nullptr;

public:
	List1();
	~List1();

	void insert(const T&);	//referencia
	const T& get();			//referencia
	void erase(const T);	//toto sa riesi inak (vecsinou cez iteratori ktore nemas implementovane)
	//...
};

template <class T> 
void List1<T>::insert(const T& value){
	item *newItem = new item(value);	//tu sa vyuzie ten novy konstruktor z item
	newItem->next = head;
	head = newItem;
}

//---------------------------------------------------
template <class T> struct Stack1{
private:
	T *arr;
	/*
	 * velkost bude zrejme nezaporna, cize radsej pouzi 'unsigned' alebo 'size_t' co je vecsinou 'unsigned long'
	 * nemusis potom kontrolovat ci uzivatel nezadal zaporne cislo
	 */
	size_t size;	
	size_t index;
	size_t sp;

public:
	Stack1(size_t, size_t);
	~Stack1();

	//provizorně

	Stack1(const Stack1 &s):
	//lepsi sposob inicializacie (aj ked pri integeroch je to jedno):
	sp(s.sp), 
	size(s.size), 
	index(s.index){	
		/*
		this->sp = s.sp;
		this->size = s.size;
		this->index = index;
		*/

		//this->arr = s.arr;		//toto nestaci, ty musis spravyt hlbkovu kopiu
		
		this->arr = new T[size];
		/*
		 * 
		 * treba prekopyrovat vsetky prvky z pola 's.arr' do 'arr'
		 */
		for(size_t i = 0; i < size; ++i){
			/*
			 * T musi mat operator=, ak by si to chcel bez neho tak musis pouzit placement new alebo malloc 
			 *   a volat konstruktory a destruktory rucne
			 */
			arr[i] = s.arr[i];			
		 }
	}
	
	

	//...
};
Nahlásit jako SPAM
IP: 95.105.157.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
marpit0
Stálý člen
13. 3. 2013   #24
-
0
-

Tak kompilace OK, zítra si s tím ještě pohraji. Všem děkuji za rady a jsem rád, že jsem se něco nového přiučil. 

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
marpit0
Stálý člen
15. 3. 2013   #25
-
0
-

Zajímavé je, že nyní se vůbec do seznamu položka (zásobník) nepřidá. Bylo mi divné, že nefungují výpisy, tak hned po plnění seznamu jsem provedl test, zda se něco uložilo a nikoliv. 

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
marpit0
Stálý člen
18. 3. 2013   #26
-
0
-

Tak nakonec vše vyřešeno, všem děkuji za poskytnuté rady. 

Nahlásit jako SPAM
IP: 78.102.62.–
MarPit
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 120 hostů

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý