• No results found

Lösningsförslag och rättningsmall för tentamen i DD2387 Programsystemkonstruktion med C++

N/A
N/A
Protected

Academic year: 2021

Share "Lösningsförslag och rättningsmall för tentamen i DD2387 Programsystemkonstruktion med C++"

Copied!
4
0
0

Loading.... (view fulltext now)

Full text

(1)

Lösningsförslag och rättningsmall för tentamen i DD2387 Programsystemkonstruktion med C++

Datum: Tisdag 20 oktober 2009, 8-12 (rättning 13-14)

Rätta mycket nogrannt. Allt som är fel ska markeras. Avgör därefter om det är ett allvarligt fel eller inte. Enstaka allvarliga fel behöver inte ge underkänt. Lycka till!

1. Att söka sekvenser

(a)FRA-lagen är på tapeten igen. Man ska kunna söka igenom delar av internet efter delmängder av ännu inte helt definierade sökmängder. Detaljerna i denna “sequrity search” är höljt i dunkel.

Skriv en generell typparametriserad funktion SeqSearch som tar fyra parametrar. Parametrarna definerar två sekvenser i godtycklig mängd. Funktionen ska returnera huruvida den andra sekvensen är en delsekvens av den första. Exempel: Exempel: {1 2 3} är en delsekvens av {1 2 3 4} och {2 4} är en delsekvens av {1 2 3 4} medan varken {3 2} eller {2 2} är en delsekvens av {1 2 3 4}. Sökning efter tomma mängden ska ge falskt svar.

Algoritmen är ungefär, gå igenom det stora intervallet och kontrollera om ett element även finns i delsekvensen.

Sökningen är sann om alla delsekvensens element påträffats i ordning.

Ett sätt att definera en mängd som funktionen ska operera på är att skicka två iteratorer. Jämför med hur t.ex. stl::sort anropas.

template<class It1, class It2>

bool subseq(It1 it1, It1 end1, It2 it2, It2 end2) {

if (it2 == end2) return false;

for(; it1 != end1; ++it1) {

if(it2 != end2 && *it1 == *it2) it2++;

}

return it1 == end1 && it2 == end2;

}

Man kan även definera intervallet med en iterator och ett heltal som anger antal element. På sätt och vis kan det ge felsäkrare kod, i lösningsförslaget så förutsätts end1 komma efter it1 och någon koll görs inte. Allvarligt fel är att deklarera någon parameter som pekare (t.ex. It *) eftersom man då inte kan anropa funktionen med iteratorer. Om det är mycket fel i uppgiften att det är oklart om den överhuvudtaget gör vad den ska, gruppera felen i några stora felkoder t.ex. syntaxfel, templatefel, logikfel och markera allt som är fel.

(b)Kan man skriva funktionen så att den anropas med två olika sorters typparametrar? Motivera ditt svar.

Ja det kan man. Dels kan det vara samma slags typ i två olika containrar men det kan också vara olika typer i olika containrar. T.ex. vector<int>::iterator och list<long>::iterator. Det ställer krav på typparametrarna att de kan jämföras med operator== observera att det blir skillnad på *it1 ==

*it2 och *it2 == *it1. Det är inte allvarligt att inte kunna svaret på denna fråga men man måste ha försökt svara. Om svaret är alldeles jättetokigt kan det vara allvarligt.

1

(2)

2. Listade terrorister

Den nya lagen kan förmodligen göra det lättare att hitta terrorister och spåra deras finansieringsverksamhet. För att hålla reda på misstänkta sifferkombinationer lägger man till siffrorna i en enkellänkad lista på följande vis:

void insert(Nod * & p, int x) { if (p == 0)

p = new Nod(x);

else

insert(p->next, x);

}

(a)En java/pythonprogrammera tycker det är märkligt att koden fungerar. Förklara varför koden fungerar och varför samma kod inte fungerar i språk som python och java som inte har referensparametrar.

Om man skickar som värdeparameter blir det en lokal pekare som jämförs och tilldelas. Utanför funktionen är pekaren inte giltig och programmet kommer att läcka minne eftersom minnet som allokeras inte frigörs. Som referensparameter så ändras pekaren i anropande scope.

(b)Nu är det inte bara siffror man vill lista utan alla möjliga skumma element. Implementera en typparametri- serad Nod som fungerar med din insert nedan.

(c)Implementera en ny förbättrad rekursiv typparametriserad insert som sorterar in elementen i listan på något sätt.

template <class T>

struct Nod {

Nod(T x) : data(x), next(0) {};

T data;

Nod * next;

};

template <class T>

void insert(Nod<T> * & p, T x) { if (p == 0) {

p = new Nod<T>(x);

} else {

if (p->data > x) {

Nod<T> * tmp = new Nod<T>(x);

tmp->next = p;

p = tmp;

} else

insert(p->next, x);

} }

Allvarliga fel är grova algoritm fel som oändlig loop. Icke allvarligt fel att glömma initiera nodens medlemmar.

(d)Vilka krav ställer din kod på det typparametriserade datat?

Lösningsförsöagets kod ställer krav på operator>, se if-sats. Man kan implementera med operator<, operator<= eller operator>= det är allvarligt att inte identfiera vilken jämförelse-operator man använder. Koden använder sig också av kopieringskonstruktorn se initieringslistan för Nod. Om man istället skrivit

Nod(T x) : next(0) { data = x;

};

Så hade defaultkonstruktorn och tilldelningsoperatorn använts. Att missa vilka konstruktorer datat använder är inte ett allvarligt fel om man har rätt på Rule of three i fråga 5b. Annars är det allvarligt.

2

(3)

3. Funktorn fra Norge

I Norge undrar man hur FRA-lagen är funtad. Man pekar på suspekta funktioner som borde kräva tillstånd. Istället för att använda funktionspekare så kan man använda funktorer istället. Hitta på och implementera en helt egen exempelkod med en funktor (även kallad funktionsobjekt)som använder sig av tillstånd för att avgöra vad som ska hända.

struct A { int x;

int operator()(int y) { if (x > 1000) {

x = 0;

return 13; // Returnera 13 ibland } else {

return x*y;

x++;

} } };

Skillnaden mellan funktionspekaren och funktorn är att den senare kan använda en medlemsvariabel för att lagra tillstånd mellan körningarna. I exemplet ovan räknar funktionen fel var 1000:e gång. Det är allvarligt fel att inte definera operator()(). Om man inte använt en medlemsvariabel för sitt beroende är det inte allvarligt fel. Har man inget beroende alls (trots muntlig instruktion) så ska det markeras men det är upp till er om ni anser det vara allvarligt.

4. Att lägga ihop ett och annat

(a)Det blir mycket data att analysera i kablarna. Man måste ha huvudet på skaft för att få lägga ihop A och B.

Implementera A och B så att följande kod kompilerar. Var noga med const och referenser.

struct B {

void consider(int x) const {};

};

struct A {

int operator+=(B b) {return 3;}

};

void LeggIhop(A a, const B & b) { b.consider(a += b);

}

Returvärdet från operator+= måste matcha parametern i consider. Det är mycket allvarligt att göra fel på const. Observera att parametern till operator+= antingen är en kopia eller const-referens men absolut inte icke-const-referens. Övriga fel är inte allvarliga om de inte är allvarliga fel :)

(b)Vad används const till i allmänhet i C++?

Används till att skrivskydda minne i compile-time och ge kompileringsfel om man försöker skriva till det minnet. Används för att flagga medlemsfunktioner (metoder) som inte får skriva på medlemsva- riabler.

(c)Ge ett exempel på när det skulle kunna vara befogat att använda const_cast i C++

Man kan tänka sig slippa kodupprepning om man har identiska metoder en const och en icke-const.

Då skulle den ena kunna ropa på den andra implementationen efter att först gjort const_canst. När allt är klart kan man föra const_cast tillbaka.

3

(4)

5. På spaning efter den tid som flytt

(a) FRA-debatten har ärvt kommunikationsproblemen som fanns redan från början om vad lagen egent- ligen handlade om. Många som lever i den virtuella verkligheten som kallas internet har svårt att hålla reda på vad som gäller. Vad skriver programmet nedan ut när man kör det?

#include <iostream>

using namespace std;

struct FRA_Old_Radio {

virtual void what() { cout << "Vi spanade i luften" << endl; };

};

struct FRA_2008_kabel : FRA_Old_Radio {

virtual void what() { cout << "Vi spanar i kablar och i luften" << endl; };

int m_number;

FRA_2008_kabel() : m_number(17) {};

FRA_2008_kabel(const FRA_Old_Radio & x) : m_number(4711) {};

Observera att Fra_kabel_2008 inte har en kopiekonstruktor och en sådan kommer att skapas vid behov

};

struct FRA_2009_extra_domstol : FRA_2008_kabel {

virtual void what() { cout << "Vi spanar bara om det är OK" << endl; } };

void evaluate(FRA_2008_kabel m) { // analyseras noga m.what();

}

int main() {

FRA_2009_extra_domstol c;

FRA_Old_Radio & a = c;

a.what();

evaluate(c);

FRA_2008_kabel b1;

FRA_2008_kabel b2 = b1; // Kopiering, kopiekonstruktor skapas cout << "Antal kablar = "

<< b2.m_number << endl;

return 0;

}

UTSKRIFT:

Vi spanar bara om det är OK Vi spanar i kablar och i luften Antal kablar = 17

Markera i koden var man tänkt fel om det är fel i utskriften. T.ex. måste man vara observant på att evaluate konstruerar en FRA_kabel kopia och “skär av” c-objektet i main (slicing på engelska).

(b)Det är nog viktigt att FRA följer reglerna som definerats. Rule of three kallas en regel som handlar om metoder som implicit kan skapas även om man inte definerat dem själv. Vilka metoder är det frågan om?

Kopiekonstruktorn, tilldelningsoperatorn och destruktorn. Det är inte fel att nämna defaultkonstruktorn.

4

References

Related documents

För att parera bristerna i denna inte helt glasklara logik så tänker skolan tvångsinskriva studenter på en obligatorisk kurs i BSB-byråkrati, en kurs som man inte kan examineras i

Markera felet på tentan i marginalen (samma fel kan härledas till två ställen ibland) och skriv utförlig kommentar i tabellen nedan samt, om lämpligt, kort kommentar på tentan

The problem appears restricted to 30GB first generation Zune players. Later 80GB and 120GB models appear to

Givet ett kontor, NewDeal, som ärvt sina metoder från OldWay, så får man två olika börsindex från en och samma kontorsinstans beroende på hur man refererar till det.. struct NewDeal

Den sista radens operator[] skriver i strängen. Alltså måste vi allokera nytt minnesutrymme och kopiera över strängen innan vi skriver i det nya minnesutrymmet. Det är detta som

b) Typkontroll av argument och returvärde, minskad risk för syntaxfel, de- buggning, mallar kan specialiseras, funktioner kan överlagras på antal element, makron kan inte

const A &amp; ger två olika överlagringar av funk- tionen boo eftersom de två överlagringarna exponerar olika gränssnitt för an- vändaren (det ena kan ändra indatat, det andra

Obs: Dessa lösningar är just lösningsförslag.. A-objektet måste allokeras dynamiskt, vilket kan ta tid om det blir många små objekt som ska allokeras och avallokeras. Det