• No results found

TDIU20. Pontus Haglund. Institutionen för datavetenskap

N/A
N/A
Protected

Academic year: 2022

Share "TDIU20. Pontus Haglund. Institutionen för datavetenskap"

Copied!
54
0
0

Loading.... (view fulltext now)

Full text

(1)

TDIU20

Pontus Haglund

Institutionen för datavetenskap

(2)

1 Vad gjorde vi förra gången?

Felhantering Operatorer Typkonvertering

2 Grundläggande om pekare 3 New

4 Destruktorer 5 Composition

(3)

Dagens föreläsning

1. Pekare

‚ new

‚ delete

‚ avreferering

‚ adress

‚ nullptr 2. Objektorientering

‚ Composition

‚ Nästlad klass

(4)

1 Vad gjorde vi förra gången?

Felhantering Operatorer Typkonvertering

2 Grundläggande om pekare 3 New

4 Destruktorer 5 Composition

(5)

Vad gjorde vi förra gången

Kom ihåg att ni alltid kan gå tillbaka till förra föreläsningen och se slides i sin helhet.

‚ Felhantering

‚ Operatorer

‚ binära

‚ unära

‚ interna

‚ externa

‚ Typkonvertering

‚ static_cast

‚ operatorer

‚ konstruktorer

(6)

5 / 52

Felhantering i c++

‚ Testar att göra övre blocket

Vid fel (en throw) hoppa till ett av catch‐blocken

‚ Fel kastas upp en nivå i programmet

try //Försök göra {

}

//Fånga exception catch(logic_error& e) {

}

catch(...) {

}

(7)

Att tänka på

‚ try är i princip lika snabbt som vilken annan kod som helst

‚ Exceptions är VÄLDIGT långsamma när du kastar dem

‚ Använd endast i exceptionella situationer

‚ Använd INTE exceptions som en styrstruktur

‚ Mycket långsammare

‚ Dåligt praxis

(8)

7 / 52

Binära operatorer

//Exempel c1 + c2;

c3 = c1;

cout << c3;

//Vad C++-kompilatorn "ser"

c1.operator+(c2);

c3.operator=(c1);

cout.operator<<(c3);

class Complex {

public:

Complex operator+(Complex const& rhs) const;

Complex& operator=(Complex const& rhs);

//...

};

std::ostream& operator<<(std::ostream& lhs, Complex const& rhs);

(9)

Unära operatorer

Har 1 operand. Vår klass är den operanden.

//Exempel c1++; //post ++c1; //pre --c1; //pre c1--; //post -c1; //???

//Hur c++ ser det

c1.operator++(int{}); //?

c1.operator++();

c1.operator--();

c1.operator--(int{}); //?

c1.operator-();

//Objektet är vänstersidan //I Complex.h

class Complex {

public:

//...

Complex& operator++();

Complex operator++(int);

Complex& operator--();

Complex operator--(int);

Complex& operator-();

//...

};

postinkrement är lite av ett fulhack...

(10)

9 / 52

Typomvandling

‚ Att omvandla en typ till en annan

‚ Exempelvis göra om en int till en double

‚ Varför!

‚ Hur?

(11)

static cast

‚ Kontrolleras compile time

‚ Krävs att objektet vet hur det konverteras till typen eller visa versa

string cs1 = static_cast<string>( Complex{1, 3} );

Complex c{1, 3};

string cs2 = static_cast<string>( c );

‚ Hur kan vi se till att Complex vet hur den skall konverteras till string?

(12)

11 / 52

Hur vet klassen?

Genom att lägga till den operatorn i klassen. Objektet vet hur den kan konverteras till målet

//Unary operator //Medlemsfunktion

Complex::operator string() {

return to_string();

}

class Complex {

//...

operator string();

operator int();

//...

}

Observera:

‚ Ingen returtyp

‚ Fungerar för andra typer

(13)

Typkonverterande konstruktorer

Målet vet hur objektet kan konverteras till sig

‚ konstruktorn sköter

konvertering från en annan typ till din typ

//h-fil class Complex {

//...

// Konstruktor som tar en parameter av typen Complex(std::string const& str);

//...

}

(14)

1 Vad gjorde vi förra gången?

Felhantering Operatorer Typkonvertering

2 Grundläggande om pekare 3 New

4 Destruktorer 5 Composition

(15)

Minne

‚ Datorns minne löper från 0‐N

‚ N = minnetsstorlek ‐ 1

‚ Består av bytes

‚ Siffran i intervallet är platsen, adressen

‚ 1 megabyte är 0 till 220‐1

‚ Vi kan visualisera minnet

(16)

15 / 52

Vad har en adress?

‚ Allt vi lägger i minnet har en adress

‚ Vanligtvis använder vi variabler för att komma åt den biten av minne

‚ Men vi kan också lagra och manipulera adresser

// Ger oss en int-stor bit av minnet // Vi kan komma åt minnet med variabeln int var{10};

// Ger oss en char-stor bit av minnet // -||-

char var2{'h'};

(17)

Lagra adress

// Vad händer?

#include <iostream>

using namespace std;

int main() {

int var{};

int* ptr{};

cout << ptr << endl;

}

(18)

17 / 52

Lagra adress

// Vad händer?

#include <iostream>

using namespace std;

int main() {

int var{17};

int* ptr{17};

cout << ptr << endl;

}

(19)

Lagra adress

// Vad händer?

#include <iostream>

using namespace std;

int main() {

int var{17};

int* ptr{var};

cout << ptr << endl;

}

(20)

19 / 52

Lagra adress

// Vad händer?

#include <iostream>

using namespace std;

int main() {

int var{17};

int* ptr{&var};

cout << ptr << endl;

}

(21)

Avreferera en adress

#include <iostream>

using namespace std;

int main() {

int var{17};

int* ptr{&var};

cout << *ptr << endl;

// ^^^^

// avreferering med * operatorn }

(22)

21 / 52

Nullptr

int main() {

int* ptri{nullptr};

cout << ptri << endl;

}

int main() {

int* ptri{nullptr};

cout << *ptri << endl;

}

0

Segmentation fault

nullptr, inte 0 eller NULL!

(23)

sizeof

Storleken i chars (bytes), är en operator Kontroll av storleken på ett heltal och en adress

#include <iostream>

using namespace std;

int main() {

int var{17};

int* ptr{&var};

cout << sizeof(var) << endl;

cout << sizeof(ptr) << endl;

}

(24)

23 / 52

sizeof

Kontroll av storleken på två (samma) heltal

#include <iostream>

using namespace std;

int main() {

int var{17};

int* ptr{&var};

cout << sizeof(var) << endl;

cout << sizeof(*ptr) << endl;

}

(25)

sizeof

Kontroll av storleken på en sträng och en adress

#include <iostream>

using namespace std;

int main() {

string var{"12345678901234567890"};

string* ptr{&var};

cout << sizeof(var) << endl;

cout << sizeof(ptr) << endl;

}

(26)

25 / 52

sizeof

Kontroll av storleken på två (samma) strängar

#include <iostream>

using namespace std;

int main() {

string var{"12345678901234567890"};

string* ptr{&var};

cout << sizeof(var) << endl;

cout << sizeof(*ptr) << endl;

}

(27)

Stjärna och Ampersang

Unära operatorn “Stjärna” *

‚ I uttryck framför pekare: Avreferera (gå till adress)

‚ I deklarationer: Skapa adressvariabel (pekare) Unära operatorn “Ampersang” &

‚ I uttryck framför variabel: Hämta variabelns adress

‚ I deklarationer: Skapa referensvariabel (alias till variabel)

Notera 1: Båda operatorerna finns även i binära varianter Notera 2: “variabel” ovan inkluderar “pekarvariabel”

(28)

27 / 52

Stjärna och Ampersang cont.

int var{4};

int* ptri{ &var }; // Pekardeklaration och adressoperatorn cout << *ptri; // Avreferering

// Tre referensdeklarationer

ostream& operator<<(ostream& lhs, Complex const& rhs) {

//...

}

(29)

Vad händer här?

Ändras adressen eller vad som ligger på den adressen?

int var{42};

int* ptri{&var};

ptri = 109;

cout << var << endl;

(30)

29 / 52

Vad händer här?

Ändras adressen eller vad som ligger på den adressen?

int var{42};

int* ptri{&var};

*ptri = 109;

cout << var << endl;

(31)

Felhantering Operatorer Typkonvertering

2 Grundläggande om pekare 3 New

4 Destruktorer 5 Composition

(32)

31 / 52

Vad gör new?

‚ Vilka delar av minnet allokeras till c++ vid start?

‚ New ger oss minne i heapen / free store

‚ Massor av ansvar...

(33)

Varför behövs både stack och heap(new)?

Varför pekare ‐ räcker det inte med vanliga variabler?

Varför new ‐ räcker det inte med vanliga variabler?

I alla tidigare slides behövs varken pekare eller new!

Men vad händer här?

int* give_me_more_memory() { int memory{}

int* ptri{&memory}

return ptri // serious problem!

}

int main() {

int* ptri{ give_me_more_memory() }

*ptri = 4711 }

(34)

33 / 52

Minnesallokering på heapen och nåbar läcka

Minnesläcka: Vad händer här?

int* give_me_more_memory() {

int* ptri{ new int{} };

return ptri; // who is responsible?

}

int main() {

int* ptri{ give_me_more_memory() }

*ptri = 4711 cout << *ptri

} // leak: serious problem

(35)

Onåbar minnesläcka och återlämning med delete

Minnesläcka: Vad händer här?

int main() {

int* ptri{ give_me_more_memory() }

*ptri = 4711 cout << *ptri

ptri = give_me_more_memory() // leak: serious problem delete ptri

}

(36)

35 / 52

Ansvarsfördelning och minnestätning

void free_up_this_memory(int* adr) { delete adr;

}

int main() {

int* ptri{ give_me_more_memory() };

*ptri = 4711;

cout << *ptri;

free_up_this_memory(ptri);

ptri{ give_me_more_memory() };

*ptri = 17;

cout << *ptri;

free_up_this_memory(ptri);

}

(37)

Fortfarande finns en enklare lösning

int main() {

int* ptri{ new int{4711} };

cout << *ptri;

delete ptri;

int* ptri{ new int{17} };

cout << *ptri;

delete ptri;

}

(38)

37 / 52

Se upp för ogiltiga pekare!

int main() {

int* ptri{ new int{4711} } cout << *ptri

delete ptri

*ptri = 17 // serious problem!

cout << *ptri // serious problem!

}

(39)

Se upp för stackadresser!

int main() {

int var{17};

int* ptri{ new int{4711} } cout << ptri

delete ptri ptri = &var cout << ptri

delete ptri // serious problem!

}

(40)

39 / 52

Enklast är ändå bäst och säkrast

int main() {

int ptr{4711};

cout << ptri;

int ptr{17};

cout << ptri;

}

Så hur blir pekare meningsfulla?

(41)

Dynamisk datastruktur!

Med verktygen pekare och new kan vi skapa datatyper som går att bygga ut!

struct data_and_pointer {

int stored_data;

data_and_pointer* more_memory;

};

(42)

41 / 52

void* och cast

‚ Undvik void*

‚ Vid hantering av pekare och new är vi på en låg nivå

‚ Typsystemet är vårt sista skydd

‚ Poängen är att ni ska låta bli i nästan alla fall

void* pv = new int{0}

*pv = 2 // Error, varför?

int pi{pv} // Error, varför?

pv[1] // Not subscriptable int* pi = static_cast<int*>(pv)

(43)

Felhantering Operatorer Typkonvertering

2 Grundläggande om pekare 3 New

4 Destruktorer 5 Composition

(44)

43 / 52

Block och destruktorer

‚ När en variabel går ut ur scope kommer den destrueras

‚ När ett objekt destrueras körs dess destruktor

‚ Ett objekt destrueras när dess minne avallokeras

‚ Rekursivt

{

vector<int> v{};

v.push_back(4);

cout << v.at(0) << endl;

} //Här destrueras v

class Array {

public:

Array();//Konstruktor

~Array();//Destruktor private:

//array containing data int* data;

}

(45)

Block och destruktorer

class Array {

public:

Array(int size);//Konstruktor

~Array();//Destruktor private:

//array containing data int* data;

}

Array::Array(int size) : data{new int[size]}

{}

Array::~Array() {

delete[] data;

}

(46)

45 / 52

Destruktor vs Konstruktor

Det är Konstruktorns jobb att initiera datamedlemmarna korrekt.

Det är destruktorns jobb att destruera datamedlemmarna korrekt.

(47)

Pekare och medlemmar

class Array {

public:

Array(int size);

~Array();

void add(int index, int value);

int get(int idx) const;

private:

int* data;

};

int main() {

Array* pa = new Array{4};

pa.add(0, 4); // Syntaxfel (*pa).add(0, 4); // Vad? Hur?

pa -> add(0, 4); // Skillnad?

}

(48)

47 / 52

Destruktor vs Konstruktor konceptuellt

Destructors are cenceptually simple but are the foundation for many of the most effective C++ programming

techniques. The basic idea is simple:

‚ Whatever resources a class object needs to function, it acquires in a constructor.

‚ During the object’t lifetime it may release resources and acquire new ones.

‚ At the end of the object’ts lifetime, the destructor releases all resources still owned by the object.

Från: Bjarne S. 2014 Programming Principles...

(49)

Felhantering Operatorer Typkonvertering

2 Grundläggande om pekare 3 New

4 Destruktorer 5 Composition

(50)

49 / 52

Vad är composition

‚ Nyckelkoncept inom OOD och OOP

‚ Medlemmen är en del av objektet

‚ Medlemmen kan bara tillhöra ett objekt åt gången

‚ Medlemmens Lifetime styrs av objektet

‚ Medlemmen känner inte till objektet

(51)

UML

‚ Composistion visas med ifylld diamant

‚ Är en del av

‚ Kardinalitet

(52)

51 / 52

Vi tänker oss en stack

‚ Vad är en stack?

‚ Hur kan vi implementera en stack?

‚ Med pekare?

‚ Syntaktiskt‐/Semanstiskt korrekt

Head

Node

Node

5

10

(53)

Nästlad klass

‚ Tydligt relation mellan Element och Stack

‚ Inkapslad trots public åtkomst

‚ Vilken klass hör vad till?

class Stack { public:

Stack();

Stack(std::initializer_list<int> il);

~Stack();

void push(int v);

int pop();

std::string to_string();

bool empty();

private:

struct Element { Element* next;

int value;

};

Element* first;

};

ostream& operator<<(ostream& os, Stack const& lhs);

(54)

www.liu.se

References

Related documents

Å ena sidan kan man argumentera att om en faktisk separation fungerar som ett exempel för andra regioner, och därmed ökar sannolikheten att dessa regioner också söker en

Årets politikervecka på Gotland gästades i år av två kvinnor från de västsahariska flyktinglägren, som var inbjudna av Nät- verket för ett fritt Västsahara..

Och – märkligast av allt – trots att arbetslös- heten går mot rekordsiffror och den förda klass- politiken verkligen slår sönder många människors tillvaro, växer stödet

Eleverna förväntades ha kunskap om när man använder stor bokstav, men det var tydligt, eftersom flera av eleverna frågade mycket, att det fanns en grupp elever som inte hade förstått

Genom att ifrågasätta kunders önskemål finns risk för att kunden väljer en annan retuschör, vilket informant A menar händer ifall hon skulle vägra manipulera en bild till något

Dessa svårigheter behöver lyftas då målet med mödrahälsovård i Sverige är en jämlik vård, där alla får en möjlighet till bättre hälsa för mor och barn. Kanske kan

Under den andra Power Point-lektionen gör Johan visserligen samma uppgift som de andra, men han kommunicerar inte kring den, Han ställer några enstaka frågor till läraren när han

Sådan assisterad kroppslig omvårdnad kan utgöra en väsentlig del av en palliativ omvårdnad för äldre personer på vård- och omsorgsboende i livets