Lösningsförslag i 2D1387 Programsystemkonstruktion med C++
1. virtual-deklarationen av speak medför att det blir subklassens implementa- tion av speak som körs. I anropet till make_a_statement_cop kopieras endast basklassdelen.
Sammanslagningen ger synergieffekter Det står på agendan
Nu måste vi fokusera på kärnverksamheten Nu måste vi fokusera på kärnverksamheten Sammanslagningen ger synergieffekter
2. När man skriver mallar måste man tänka på vilka krav man ställer på sina typparametrar. I första fallet kan vi anta att de vanliga operatorerna är defini- erade.
template <class T>
int gallra(T * begin, T * end, int s) { int retur = 0;
for (T * i = begin; i != end; i++) { if (*i >= s) retur++;
}
return retur;
}
I det andra fallet måste vi själva deklarera det jämförande funktionsanropet.
Nedan finns några förslag. Beroende på hur man skriver jämförelsen kan det bli en metod i endera klassen eller kanske en fristående funktion. Jag tycker det är sämre att lägga metoden i vektorelementets klass men jag kan godkänna bra motiveringar.
template <class T, class S>
int gallra(T * begin, T * end, S s) { int retur = 0;
for (T * i = begin; i != end; i++) {
if !(*i < s) retur++; // kan skrivas (s < *i) }
return retur;
}
class T {
bool operator< (B b) // Vektorvärdena måste känna till B // ...
class B {
bool operator< (T t) // Jämförelseklassen känner till vektorvärdet // ...
bool compare(B b, T t) // Funktionen känner till båda
1
3.
a) Det finns flera fel med den här metoden. Dels så kopieras aldrig gamla kunder över till nya vektorn, dels så avallokeras inte den gamla vektorn vilket betyder att metoden läcker minne, dels så uppdateras inte custo- mer_capacity. En kortfattad formuleringen skulle kunna vara. Metoden tappar gamla kundvektorn och läcker minne
b) Det är framför allt if-saten som är tokig och behöver illustreras.
if (nr_of_customers >= customer_capacity) {
customers = new Customer [customer_capacity * 2];
c) Se push_back i lab1.
d) Man behöver fånga bad_alloc med ett try/catch-block. För att skicka vidare kan man antingen kasta vidare ett annat undantag eller så kan man returnera något om man ändrar void i metodhuvudet. Det kan vara en god ide att skicka med kundens data (Customer a) i undantaget eller i returvärdet.
Assert är fel sätt i det här fallet eftersom det avbryter programmet möjli- gen skulle det kunna godkännas med en bra motivering och rapportering i en logfil.
e) Titta i konstruktorerna, kolla om de allokerar minne. Titta speciellt efter copy-konstruktorn. Den bör se ut som i lab1 vektorklass. Kolla att de- struktorn kör delete [] på customers. Kolla efter operator= som kommer att se ut ungefär som i lab1 vektorklass.
2
4.
a) Referensräkning med copy-on-write är en teknik för att spara minne i strängklassen. Istället för att alltid allokera nytt minne för varje namn så kan strängar med samma innehåll dela ett minnesutrymm. Till det behövs en hjälpklass som allokerar minnet och som har en referensräknare (en instansvariabel) som håller reda på hur många strängar som refererar den.
b) s2 = s1; // operator=
char c = s2[5]; // operator[] const s2[5] = ’L’; // operator[]
s2 = s1;
Metoden operator= ska i basfallet sätta om this att peka ut parameterns minnesutrymme. Dessutom räkna ner sin föregående referensräknare och räkna upp den andra.
Om referensräknaren når noll ska minne frigöras med delete.
Det är som vanligt bra att ta hand om specialfallet:
s1 = s1;
s2[5] = ’L’;
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 är copy-on-write.
char c = s2[5];
Om vi bara ska läsa i strängen är det onödigt att kopiera till en ny sträng.
Därför vill vi ha en operator[] const.
3
c) Båda pekar på samma minnesutrymmet men p1 är const-deklarerad och får inte ändra på minnesutrymme. Därför kommer operator[] const (se b) att anropas.
d) Med p2 kan man få problem med våran referensräknarklass. Visserligen sker ingen skrivning till strängen men strängklassen kan inte skydda sig mot *p2 = ’X’;
f ) Man kan tänka sig att operator[] alltid kopierar till nytt minne. Då kan man inte garantera konstant tid för: char * p2 = &s1[5];
Man kan tänka sig en statusflagga i klassen och kopiera senare.
e) p1 är read-only och kan inte skriva i strängen.
4