54
TDIU20 Pontus Haglund Instuonen för datavetenskap

TDIU20 - ida.liu.se

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

TDIU20Pontus Haglund

Institutionen för datavetenskap

1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering

2 Grundläggande om pekare3 New4 Destruktorer5 Composition

2 / 52

Dagens föreläsning

1. Pekare

‚ new

‚ delete

‚ avreferering

‚ adress

‚ nullptr

2. Objektorientering

‚ Composition

‚ Nästlad klass

1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering

2 Grundläggande om pekare3 New4 Destruktorer5 Composition

4 / 52

Vad gjorde vi förra gången

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

‚ Felhantering‚ Operatorer

‚ binära‚ unära‚ interna‚ externa

‚ Typkonvertering‚ static_cast‚ operatorer‚ konstruktorer

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 exceptioncatch(logic_error& e){

}catch(...){

}

6 / 52

Att tänka på

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

‚ 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

7 / 52

Binära operatorer

//Exempelc1 + 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);

8 / 52

Unära operatorer

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

//Exempelc1++; //post++c1; //pre--c1; //prec1--; //post-c1; //???//Hur c++ ser detc1.operator++(int{}); //?c1.operator++();c1.operator--();c1.operator--(int{}); //?c1.operator-();

//Objektet är vänstersidan//I Complex.hclass Complex{public://...Complex& operator++();Complex operator++(int);Complex& operator--();Complex operator--(int);Complex& operator-();//...

};

postinkrement är lite av ett fulhack...

9 / 52

Typomvandling

‚ Att omvandla en typ till en annan

‚ Exempelvis göra om en int till en double

‚ Varför!

‚ Hur?

10 / 52

static cast

‚ Kontrolleras compile time

‚ Krävs att objektet vet hur det konverteras till typeneller 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 skallkonverteras till string?

11 / 52

Hur vet klassen?

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

//Unary operator//MedlemsfunktionComplex::operator string(){return to_string();

}

class Complex{//...operator string();operator int();//...

}

Observera:

‚ Ingen returtyp

‚ Fungerar för andra typer

12 / 52

Typkonverterande konstruktorer

Målet vet hur objektet kan konverteras till sig

‚ konstruktorn sköterkonvertering från en annan typtill din typ

//h-filclass Complex{//...// Konstruktor som tar en parameter av typenComplex(std::string const& str);//...

}

1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering

2 Grundläggande om pekare3 New4 Destruktorer5 Composition

14 / 52

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

15 / 52

Vad har en adress?

‚ Allt vi lägger i minnet har enadress

‚ Vanligtvis använder vi variablerför att komma åt den biten avminne

‚ Men vi kan också lagra ochmanipulera adresser

// Ger oss en int-stor bit av minnet// Vi kan komma åt minnet med variabelnint var{10};// Ger oss en char-stor bit av minnet// -||-char var2{'h'};

16 / 52

Lagra adress

// Vad händer?#include <iostream>

using namespace std;

int main(){

int var{};int* ptr{};cout << ptr << endl;

}

17 / 52

Lagra adress

// Vad händer?#include <iostream>

using namespace std;

int main(){

int var{17};int* ptr{17};cout << ptr << endl;

}

18 / 52

Lagra adress

// Vad händer?#include <iostream>

using namespace std;

int main(){

int var{17};int* ptr{var};cout << ptr << endl;

}

19 / 52

Lagra adress

// Vad händer?#include <iostream>

using namespace std;

int main(){

int var{17};int* ptr{&var};cout << ptr << endl;

}

20 / 52

Avreferera en adress

#include <iostream>

using namespace std;

int main(){

int var{17};int* ptr{&var};cout << *ptr << endl;// ^^^^// avreferering med * operatorn

}

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!

22 / 52

sizeof

Storleken i chars (bytes), är en operator Kontroll av storlekenpå 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;

}

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;

}

24 / 52

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;

}

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;

}

26 / 52

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 tillvariabel)

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

27 / 52

Stjärna och Ampersang cont.

int var{4};int* ptri{ &var }; // Pekardeklaration och adressoperatorncout << *ptri; // Avreferering

// Tre referensdeklarationerostream& operator<<(ostream& lhs, Complex const& rhs){//...

}

28 / 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;

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;

1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering

2 Grundläggande om pekare3 New4 Destruktorer5 Composition

31 / 52

Vad gör new?

‚ Vilka delar av minnetallokeras till c++ vidstart?

‚ New ger oss minne iheapen / free store

‚ Massor av ansvar...

32 / 52

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

}

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 = 4711cout << *ptri

} // leak: serious problem

34 / 52

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 = 4711cout << *ptriptri = give_me_more_memory() // leak: serious problemdelete ptri

}

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);

}

36 / 52

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;

}

37 / 52

Se upp för ogiltiga pekare!

int main(){

int* ptri{ new int{4711} }cout << *ptridelete ptri*ptri = 17 // serious problem!cout << *ptri // serious problem!

}

38 / 52

Se upp för stackadresser!

int main(){

int var{17};int* ptri{ new int{4711} }cout << ptridelete ptriptri = &varcout << ptridelete ptri // serious problem!

}

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?

40 / 52

Dynamisk datastruktur!

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

struct data_and_pointer{

int stored_data;data_and_pointer* more_memory;

};

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 subscriptableint* pi = static_cast<int*>(pv)

1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering

2 Grundläggande om pekare3 New4 Destruktorer5 Composition

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 dataint* data;

}

44 / 52

Block och destruktorer

class Array{public:Array(int size);//Konstruktor~Array();//Destruktor

private://array containing dataint* data;

}

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

Array::~Array(){delete[] data;

}

45 / 52

Destruktor vs Konstruktor

Det är Konstruktorns jobb attinitiera datamedlemmarna korrekt.

Det är destruktorns jobb attdestruera datamedlemmarnakorrekt.

46 / 52

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?

}

47 / 52

Destruktor vs Konstruktor konceptuellt

Destructors are cenceptually simple but are the foundationfor many of the most effective C++ programmingtechniques. The basic idea is simple:

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

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

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

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

1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering

2 Grundläggande om pekare3 New4 Destruktorer5 Composition

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

50 / 52

UML

‚ Composistion visas medifylld diamant

‚ Är en del av‚ Kardinalitet

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

52 / 52

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);

www.liu.se