c++ Global pointer problem

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
kodar-holger
EF Sponsor
Inlägg: 916
Blev medlem: 26 maj 2014, 12:54:35
Ort: Karlskoga

Re: c++ Global pointer problem

Inlägg av kodar-holger »

johanos förklaring var bra och korrekt, men jag skall ändå försöka ge mig på en alternativ beskrivning. Jag tänker försöka hålla mig från begrepp som stack och heap. Det är ju trots allt ett högnivåspråk :humm: vi talar om och man skall mer tänka på vad man vill åstadkomma än hur det realiseras på hårdvaran.

int, double, QImage, QLedMatrix, QWidget och MyWindow är exempel på datatyper. När du börjar en statement med en datatyp betyder det att du vill göra en deklaration av ett namngivet utrymme för något av den datatypen. Hur länge detta utrymme är ditt beror på i vilket scope deklarationen görs.

Kod: Markera allt

int raknare;
betyder alltså att en variabel 'raknare' finns inom det scope där den är deklarerad.

När du sätter en * efter datatypnamnet betyder det att det inte är typen i sig du vill ha utrymme för utan en pekare till något av den typen. Så:

Kod: Markera allt

QImage* nisse;
Ger dig en variabel nisse som KAN peka på objekt av typen QImage.

new är en operator som skapar ett objekt/utrymme i ett globalt scope och ger dig pekaren till det tillbaka. Om du inte tar hand om pekaren så finns objektet i sjön men du kommer inte åt det. Tar du hand om pekaren så kan du skicka den hit och dit och komma åt objektet i hela det globala scopet. Objektet finns där tills du gör delete på det. Om du då har skickat runt pekare kors och tvärs så kommer dom att fortsätta peka på något som inte lägre är reserverat för dig och du kommer fortare än kvickt att bli överraskad av att något helt annat ligger där. Att skapa saker med new kräver alltså tungan i rätt mun.

C++ ger dig tillgång till den konstruktion som heter klasser. En klass är en inkapsling av kod och det data som den opererar på. Till skillnad från enkla typer som int, float och enum har klasser konstruktorer. Det är kod som körs när objektet skapas. Konstruktorn kan kräva inparametrar.

Kod: Markera allt

QImage img1(":/erik8.png");
Skapar alltså plats för en instans av klassen QImage inom deklarationens scope och ger den namnet img1. ":/erik8.png" är en parameter som skickas med till konstruktorn.

Kod: Markera allt

img1p = new QImage(":/erik8.png");
img1p är inget typnamn utan namnet på någon annan variabel som finns inom aktuellt scope. Sen är syntaxen lite annorlunda här jämfört med tidigare. Man anger parametrarna till konstruktorn efter typnamnet, men det är samma sak. Operatorn new som sagt skapar utrymmet i den globala sjön och ger dig pekaren som hamnar i variabeln img1p.

Scope avgränsas normalt av {} men i vissa fall av ; . Klassdeklarationen ger dig ett extra scope som omfattar alla metoder deklarerade i klassen.

Kod: Markera allt

{
  int a; //deklaration av a. Synlig till rad 15
  {
   int b; //deklaration av b. Synlig till rad 5
  }
  //Här finns alltså a men inte b
  for (int i=0;i<3;i++)
  {
    // Här finns i
  }
  for (int j=0;j<3;i++); //Obs elakt ;
  {
    // Här finns inte j!
  }
}
När en enkel variabel går ur scope försvinner den bara. När en variabel som är av en klass-typ försvinner körs koden i destruktorn. Pekare är enkla typer så när pekaren går ur scope händer alltså ingenting. Har man då skapat något med new så är utrymmet "förlorat". Destruktorn kommer inte att köras och ingen kommer åt objektet längre. Än en gång, använd pekare med försiktighet. En annan fälla: delete ändrar inte pekaren.

Kod: Markera allt

int* a=new int;
delete a;
//Här pekar fortfarande a på det utrymme som reserverades.
delete gör att destruktorn körs om det är en pekare till en klass.

Som du ser har jag satt * intill datatypnamnet och inte intill variabelnamnet. Jag personligen tycker det är tydligare. Det är ju inget speciellt med variabeln. Det är datatypen som är "manipulerad". Andra tycker tvärt om.
Varför blir inte img1p local variabel pss som matrix12 med anropet
Jämför kodraderna. I ena fallet finns inget typdeklaration först. Du har redan variabeln img1p som kommer någon annan stans ifrån (klassdeklarationen). I andra fallet börjar raden med datatypen QLedMatrix så där blir alltså en deklaration.

Jag tycker att det är mycket olyckligt att C och C++ inte tydligare visar vad som är deklarationer och vad som är exekverbara statements. Men så är jag ju en riktig Ada-kramare också. Men i båda språken kan ju även en deklaration leda till att kod exekveras (konstruktorer) så Ada är kanske inte jättemycket bättre på den punkten. Eller jo det är det :D . Eftersom det är så otydligt vad som är typer och variabler i C++ brukar man använda konventioner för versaler/gemener för att skilja dom åt. Ofta ges typer namn som börjar med en versal medan variabler har namn som startar med en gemen. Dessutom ges ofta variabler namn som tipsar om typen. Lästips: https://en.wikipedia.org/wiki/Hungarian_notation
Användarvisningsbild
hawkan
Inlägg: 2585
Blev medlem: 14 augusti 2011, 10:27:40

Re: c++ Global pointer problem

Inlägg av hawkan »

Tänkte tillägga det tråkiga i att det nog är värt att titta i dokumentationen hur det är tänkt att argument av pekartyp ska skapas. Det finns oftast sätt att undvika att använda den "föråldrade" pekartypen om man säger så, så i och med att man gör det så finns det nog en filosofi bakom. T,ex kanske det görs en delete() när ett objekt som referar kör sin destruktor. Gissningar men värt att kolla hur det är tänkt.

*Jag gillar pekare.
Användarvisningsbild
Oltronix
Inlägg: 408
Blev medlem: 10 december 2011, 21:24:38
Ort: Nynäs

Re: c++ Global pointer problem

Inlägg av Oltronix »

Tack för ert input.
Det har känts som jag haft en verktygslåda och plockat upp en fastnyckel eller en skiftnyckel slumpartat utan att varken förstå eller veta vad jag plockat up. Fastnyckel och skiftnyckel används till samma sak men hanteringen skiljer sig åt som bekant.

Jag har blandat ihop lokala och globala variabler. Genom att återdeklarera globala varibler som egentligen blivit nya lokala variabler som överridit de globalt deklarerade i klassdeklartionen. Jag måste hitta rätt kompilator/länkar-flaggor så jag får en varning för detta.

Även har jag blandat ihop variabel-deklarationer med instasieraingar av class-variabler. Jag har även sett konstruktorns scope om som ett överordnat scope till dess funktioner, att konstruktorns lokala varibler är synliga i konstruktonrs funktioner.

Kanske har jag blivit lite klokare när det gäller "*" som jag tycker verkar finnas både här och där och inte bara i en deklaration där de även kan finns på olika ställen.

I hope I got all right, at least a bit less wrong!

Återigen Tack!

//Erik

Ps
hawkan:Vad är
"föråldrade" pekartypen ?
ie
EF Sponsor
Inlägg: 1271
Blev medlem: 23 oktober 2006, 13:12:57
Ort: Tyresö

Re: c++ Global pointer problem

Inlägg av ie »

kodar-holger skrev:Som du ser har jag satt * intill datatypnamnet och inte intill variabelnamnet. Jag personligen tycker det är tydligare. Det är ju inget speciellt med variabeln. Det är datatypen som är "manipulerad". Andra tycker tvärt om.
Jag tillhör "de andra", då följande lätt kan misstolkas.

Kod: Markera allt

int* a, b;
I detta fall är a en pekare och b en int, fast man skulle snarare tro att både är pekare.

Kod: Markera allt

int *a, b;
Detta visar tydligare att det endat är a som är en pekare.

Tycker jag i alla fall... :)
Användarvisningsbild
ffredrik
Inlägg: 340
Blev medlem: 20 oktober 2009, 17:52:18
Ort: Göinge

Re: c++ Global pointer problem

Inlägg av ffredrik »

Jag håller med ie.
Användarvisningsbild
Jan Almqvist
Inlägg: 1580
Blev medlem: 1 oktober 2013, 20:48:26
Ort: Orust

Re: c++ Global pointer problem

Inlägg av Jan Almqvist »

Varför inte så här?

Kod: Markera allt

int* a;
int b;
Nerre
Inlägg: 26655
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: c++ Global pointer problem

Inlägg av Nerre »

Ja, jag tycker att det alltid är bättre att deklarera varje variabel för sig. Kompilatorn bryr sig inte om vilket, det är marginellt mer att skriva men blir så mycket tydligare.

Kompilatorn skiter ju i de flesta fall också i allt vad mellanrum heter, så det är bättre att skriva koden så den blir läsbar.
Skriv svar