Problem z template.

0

Pierwszy raz tworzę klasę z wykorzystaniem template. Jest to klasa wektor. Mogły mi ktoś wskazać co robię zle?

wektor.h

#pragma once
#include <string>
template < class T >
class Wektor
{
	T *s; int rozmiar;
public:
	Wektor();
	void push(T x);
	int size();
	~Wektor();
};

wektor.cpp


#include "Wektor.h"


template <class T>
Wektor<T>::Wektor():s(nullptr), rozmiar(0)
{}

template<class T>
void Wektor<T>::push(T x)
{
	delete s;
	s = new T[rozmiar + 1];
	rozmiar++;
}
template<class T>
int Wektor<T>::size()
{
	return rozmiar;
}
template<class T>
Wektor<T>::~Wektor()
{
	delete s;
}


main.cpp

Wektor<int> x;
return 0;

Bład który wyskakuje:
Error LNK2019 unresolved external symbol "public: __thiscall Wektor<int>::~Wektor<int>(void)" (??1?$Wektor@H@@QAE@XZ) referenced in function _main

2

Wrzuć wszystko do pliku *.h i zadziała. Template'y tak już mają.
Poza tym kod zawiera błędy. Kompiluje się, kiedy wrzucę wszystko do headera, ale jest nieprawidłowy, ponieważ robisz tam masę dziwnych rzeczy i to nawet nie dotyczy samych szablonów.

  • Robisz delete nie sprawdzając wskaźnika;
  • Przekazujesz generyczny obiekt przez wartość zamiast refrencją;
  • W pushu tracisz kompletnie dane, bo z przekazanym obiektem niczego nie robisz.
  • Każdy Twój push utworzy nową tablicę więc za każdym razem utracisz stare dane, bo w ogóle nie ma obsługi starych wartości.
  • To się wszystko wysypie ;)
0
grzesiek51114 napisał(a):

Wrzuć wszystko do pliku *.h i zadziała. Template'y tak już mają.
Poza tym kod zawiera błędy. Kompiluje się, kiedy wrzucę wszystko do headera, ale jest nieprawidłowy, ponieważ robisz tam masę dziwnych rzeczy i to nawet nie dotyczy samych szablonów.

  • Robisz delete nie sprawdzając wskaźnika;
  • Przekazujesz generyczny obiekt przez wartość zamiast refrencją;
  • W pushu tracisz kompletnie dane, bo z przekazanym obiektem niczego nie robisz.
  • Każdy Twój push utworzy nową tablicę więc za każdym razem utracisz stare dane, bo w ogóle nie ma obsługi starych wartości.
  • To się wszystko wysypie ;)

Oczywiscie masz racje, chciałem żeby te template zadziałały po prostu.

0

Jak powinien wyglądać destruktor, gdy jednym z typ jest typ string?
string jest sam w sobie tablica dynamiczna. Usunie się ona sama, czy muszę to jakoś obsługiwać?


~Wektor()
	{
		if(s!= nullptr)
		delete s;
	}
4

Jeśli już musisz używać new/delete (patrz: tutaj), to koniecznie pamiętaj, że każde wywołanie new musi mieć odpowiadające wywołanie delete, a new[] - delete[]. Mieszanie ich to UB. Ponadto musisz respektować regułę 3/5/0.

0
kq napisał(a):

Jeśli już musisz używać new/delete (patrz: tutaj), to koniecznie pamiętaj, że każde wywołanie new musi mieć odpowiadające wywołanie delete, a new[] - delete[]. Mieszanie ich to UB. Ponadto musisz respektować regułę 3/5/0.

Tworzę projekt na studia, nie wolno nam korzystać z STL.
Powiedziałbym, że mój problem tkwi w tym, że chciałbym używać jako "szablonowego" typu stringa. Jak powinienem to obsłużyć w destruktorze, mając na uwadze to, że nie będzie to tylko string.
Jest jakaś funkcja, która pomoże mi sprawdzić typ wskaźnika?
Jeśli uda mi się to zrobić, to jak powinien zachowywać się destruktor(bo przy powyższej implemetacji mam wyciek pamieci)?

1

string umie sprzątać po sobie jeśli trzymasz obiekt, a nie wskaźnik. Więc pytanie raczej brzmi "dlaczego masz T* s a nie T s?"
Edit: ok implementujesz tablicę dynamiczną.

1

Powiedziałbym, że mój problem tkwi w tym, że chciałbym używać jako "szablonowego" typu stringa.

@mistrzuniu1: No ale skoro tworzysz szablon to typem będzie generyk T, bo tak w sumie najrozsądniej zrobić. Tworzysz kontener na dane abstrakcyjnego typu T, który może być czymkolwiek: strukturą, klasą, prymitywem etc... IMHO string jest Ci do niczego nie potrzebny.

Jeżeli natomiast chcesz zrobić kontener i chcesz go samemu zaimplementować w szablonie to może warto posłużyć się listą, którą np. samemu napiszesz? https://4programmers.net/Forum/C_i_C++/288340-lista_jednokierunkowa_to_do_list_pomoc_dla_nooba?p=1352973#id1352973

No, bo kontener to kontener na cokolwiek chcę: taka w sumie jest idea szablonów.

1

wektor.h:

#pragma once

template < class T >
class Wektor
{
    T *s; int rozmiar;
public:
    Wektor();
    void push(T x);
    size_t size() const;
    ~Wektor();
};

wektor.cpp:

#include "wektor.h"
 
template <class T>
Wektor<T>::Wektor(): s{nullptr}, rozmiar{}
{}
 
template<class T>
void Wektor<T>::push(T x)
{
    delete s;
    s = new T[rozmiar + 1];
    rozmiar++;
}

template<class T>
size_t Wektor<T>::size() const
{
    return rozmiar;
}

template<class T>
Wektor<T>::~Wektor()
{
    delete s;
}

// To wydaje się być najbardziej sensowne rozwiązanie Twojego problemu.
template class Wektor<int>;

main.cpp:

#include <cstdlib>
#include "wektor.h"

int main()
{
    Wektor<int> x;
    
    return EXIT_SUCCESS;
}
4
Mokrowski napisał(a):

wektor.cpp:

// To wydaje się być najbardziej sensowne rozwiązanie Twojego problemu.
template class Wektor<int>;

Nie zgodzę się. To zabija całą generyczność Wektora. Najlepsze będzie przeniesienie implementacji do hpp IMHO (:

1 użytkowników online, w tym zalogowanych: 0, gości: 1