Permalänk

c++ cout ändrar variabler!

Tjo. Jag har ett litet märkligt problem.

I en kod som hanterar vektorer, kompileras och körs testprogrammet bra. Men ifall man i testprogrammet använder sig av cout mellan två testfall så kan ett fall som tidigare fungerade bli fel. Dvs cout ändrar på saker. I vårt fall ändrades innehållet i en array då vi använde cout<<array[0]<<endl; också när man skriver cout<< "Hej " << endl; innan så blir det fel enligt assert().

Är det någon som kan förklara detta märkliga beteende?

Visa signatur

Avatarkreds till: http://imgur.com/HOxIL
Alakai säger: Ryssen skrattar. Norrland hembränner på uppdrag av regeringen. Sälar dör i blyförgiftning, fulla och glada. Förvirringen är total. Kungen är nöjd.

Permalänk
Medlem

Det blir klart enklare om du kunde dela med dig av fler detaljer. Vad menar du exempelvis med "två testfall"? Innehållet kanske ändras varje gång du kör.

Visa signatur

Citera eller nämn gärna mig (@ToJa92) om du svarar på något jag skrivit.
Uppskattar du eller blir hjälpt av ett inlägg jag skrivit är jag tacksam om du gillar det.

Permalänk
Medlem

Högst troligen läser du utanför minnet som är allokerat för arrayen.

T.ex.:

int array[10]; cout << array[10] << endl;

Visa signatur

"Nothing is impossible because impossible itself says I M Possible..."

Permalänk
Skrivet av Weeblie:

Högst troligen läser du utanför minnet som är allokerat för arrayen.

T.ex.:

int array[10]; cout << array[10] << endl;

Detta förklarar inte varför cout<<"Hej"<<endl; ändrar på värden som studeras efteråt av assert()..

Visa signatur

Avatarkreds till: http://imgur.com/HOxIL
Alakai säger: Ryssen skrattar. Norrland hembränner på uppdrag av regeringen. Sälar dör i blyförgiftning, fulla och glada. Förvirringen är total. Kungen är nöjd.

Permalänk
Skrivet av ToJa92:

Det blir klart enklare om du kunde dela med dig av fler detaljer. Vad menar du exempelvis med "två testfall"? Innehållet kanske ändras varje gång du kör.

Det jag menar är att jag har en array, typ vect[].

värden i denna array är inladga på rätt platser så att

assert(vect[0] == 2.4, vect[1] == 1.3) funkar bra när inte cout har blivit anropad innan. Men ifall det står

cout << "HEJSAN" << endl;
assert(vect[0] == 2.4, vect[1] == 1.3);

Så funkar inte koden då assert hävdar att vectorn är ändrad..

EDIT: på plats 0 i vectorn ligger alltså värdet 2.4 och på plats 1 ligger värdet 1.3 innan cout anropas...

Visa signatur

Avatarkreds till: http://imgur.com/HOxIL
Alakai säger: Ryssen skrattar. Norrland hembränner på uppdrag av regeringen. Sälar dör i blyförgiftning, fulla och glada. Förvirringen är total. Kungen är nöjd.

Permalänk
Medlem
Skrivet av Mikael_Berglund:

Det jag menar är att jag har en array, typ vect[].

värden i denna array är inladga på rätt platser så att

assert(vect[0] == 2.4, vect[1] == 1.3) funkar bra när inte cout har blivit anropad innan. Men ifall det står

cout << "HEJSAN" << endl;
assert(vect[0] == 2.4, vect[1] == 1.3);

Så funkar inte koden då assert hävdar att vectorn är ändrad..

EDIT: på plats 0 i vectorn ligger alltså värdet 2.4 och på plats 1 ligger värdet 1.3 innan cout anropas...

Innehåller vektorn flyttal så kan du inte lita på att de är exakt lika med något värde – den enda garantin du har är att de ligger inom en viss felmarginal. Sedan ska du nog inte använda kommaoperatorn i assert()... posta mer kod!

Permalänk
Skrivet av You:

Innehåller vektorn flyttal så kan du inte lita på att de är exakt lika med något värde – den enda garantin du har är att de ligger inom en viss felmarginal. Sedan ska du nog inte använda kommaoperatorn i assert()... posta mer kod!

Problemet är att koden inte ligger så jag kommer åt den lätt så jag skriver ifrån huvudet. :/

Att flyttalen inte är exakta vet jag. Men eftersom assert() inte klagar så länge inte cout<<endl har används i koden så kan jag inte se att det är något problem. Ska försöka jaga rätt på koden och posta den här för er.

Visa signatur

Avatarkreds till: http://imgur.com/HOxIL
Alakai säger: Ryssen skrattar. Norrland hembränner på uppdrag av regeringen. Sälar dör i blyförgiftning, fulla och glada. Förvirringen är total. Kungen är nöjd.

Permalänk
Medlem
Skrivet av Mikael_Berglund:

Detta förklarar inte varför cout<<"Hej"<<endl; ändrar på värden som studeras efteråt av assert()..

Det gör det visst.

Ett funktionsanrop som inte optimeras bort skriver nästan garanterat över en viss mängd stackminne. D.v.s. beroende på vilken ordning dina variabler är definierade, kanske precis den del av minnet som array[10] (det 11:e elementet) referar till i en array med 10 element.

En anna orsak som kan ske när talet är flyttal är om huruvida flyttalen fortfarande är kvar i registren eller ej (oftast högre precision i registren).

Visa signatur

"Nothing is impossible because impossible itself says I M Possible..."

Permalänk
Skrivet av Weeblie:

Det gör det visst.

Ett funktionsanrop som inte optimeras bort skriver nästan garanterat över en viss mängd stackminne. D.v.s. beroende på vilken ordning dina variabler är definierade, kanske precis den del av minnet som array[10] (det 11:e elementet) referar till i en array med 10 element.

En anna orsak som kan ske när talet är flyttal är om huruvida flyttalen fortfarande är kvar i registren eller ej (oftast högre precision i registren).

Den sista orsaken du nämnde kan nog vara intressant! Vet dock inte hur jag skulle gå till väga för att fixa det ifall det är det felet.

Lyckades i alla fall få hem koden så här kommer den.

//KOMMENTAR: cpp funkar att includera men inte vector.h men de säger att header ska inkluderas! #include "vector.cpp" // inkludera din headerfil här #include <assert.h> // assert(b) ger felmeddelande om b falsk using namespace std; int main() { Vector<double> v; // ok: defaultkonstruktor ger vektor med flyttal Vector<char> *a = new Vector<char>[3]; // dynamiskt allokerade ser ut så här delete [] a; assert(v.size() == 0); // tom från början v.push_back(3.14); // lägg till ett element sist cout<< "Första cout " << v[0] << endl; assert(v.size() == 1); // nu ligger ett element i vektorn v.insert(0, 2.10); // lägg till före element 0, dvs först assert(v[0] == 2.10 && // hamnade de rätt? v[1] == 3.14); cout<< "Andra cout " << v[0] << endl; assert(v.size() == 2); // nu ligger två element i vektorn v.sort(false); // sortera i fallande ordning assert(v[0] == 3.14 && // hamnade de rätt? v[1] == 2.10); assert(v.size() == 2); // ingenting ändrat? v[1] = 2.11; // tilldelning av enstaka element; cout << "Sista cout " << v[0] << endl; const Vector<double> &vc = v; // skapa konstant referens assert(vc.size() == 2); // ok: ändrar ej vektorn som är konstant assert(vc[0] == 3.14 && // ok: ändrar ej vektorn som är konstant vc[1] == 2.11); v.erase(0); // ta bort första elementet assert(v.size() == 1); // rätt antal elelment v.clear(); // töm hela vektorn assert(v.size() == 0); // tom när alla element är borttagna // kontrollera att följande rader inte går att kompilera // vc[0] = 3.1415; // fel: tilldelning av konstant objekt // Vector<char> c = v; // fel: tilldelning av olika typer // vc.sort(); // fel: ändrar konstant objekt return 0; }

Detta komplierar och körs med output:

Första cout 3.14
Andra cout 2.1
Assertion failed: v[0] == 3.14 && v[1] == 2.10, file test_template_vec_no_header.cpp, line 26
Abort

Men ifall cout tas bort så funkar allt som det ska!

vector.h och vector.cpp finns här och här ifall detta kan hjälpa!

Tar gärna emot kritik på koden då det är mitt första riktiga c++ kodande!

Och tack för all hjälp hittills förresten!

Visa signatur

Avatarkreds till: http://imgur.com/HOxIL
Alakai säger: Ryssen skrattar. Norrland hembränner på uppdrag av regeringen. Sälar dör i blyförgiftning, fulla och glada. Förvirringen är total. Kungen är nöjd.

Permalänk
Medlem

Som You nämnde kan du kolla om talen ligger inom en viss felmarginal.

bool float_equals(float lhs, float rhs) { // Jag är inte säker på vilken konstant som skulle passa bäst. // Funktionen skulle kunna ta felmarginalen som argument för att passa // olika sammanhang. return abs(lhs - rhs) < 0.0000001; }

Övriga kommentarer:

Templates kan inte kompileras separat, utan implementationerna måste inkluderas direkt. Det är därför det bara fungerar när du inkluderar vector.cpp. Du har två val för att att kunna inkludera vector.hpp (vilket du bör göra):

  • Implementera funktionerna i en separat fil, men inkludera sedan denna sist i vector.hpp. Vanligt är att låta implementationsfilen heta något som vector.impl eller vector.hpp.impl för att skilja den från filer som ska kompileras separat.

  • Implementera funktionerna direkt i headerfilen, antingen "inline" eller efter klassdeklarationen.

I vector.cpp använder du & istället för && som logiskt OCH. I det här fallet råkar koden fungera eftersom både vänster- och högerled är ett riktiga booleska uttryck, och alltså evalueras till antingen 0 eller 1, men det ska vara &&.

Din kod är inte exception safe, och kan därför läcka minne. Ett exempel är din copy constructor. Du allokerar rätt mängd minne, men skulle sedan ett element kasta ett undantag när det kopieras kommer minnet att läcka.

Vector<T>::operator= kommer att skriva längre än sin buffer om rhs är för lång.

Detta är nog bara temporärt i din kod, men i Vector<T>::insert pekar du om vec till en temporär buffer. Du har dock den "korrekta" koden utkommenterad, vilket får mig att tro att det är temporärt.

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk
Skrivet av lajnold:

Som You nämnde kan du kolla om talen ligger inom en viss felmarginal.

bool float_equals(float lhs, float rhs) { // Jag är inte säker på vilken konstant som skulle passa bäst. // Funktionen skulle kunna ta felmarginalen som argument för att passa // olika sammanhang. return abs(lhs - rhs) < 0.0000001; }

Övriga kommentarer:

Templates kan inte kompileras separat, utan implementationerna måste inkluderas direkt. Det är därför det bara fungerar när du inkluderar vector.cpp. Du har två val för att att kunna inkludera vector.hpp (vilket du bör göra):

  • Implementera funktionerna i en separat fil, men inkludera sedan denna sist i vector.hpp. Vanligt är att låta implementationsfilen heta något som vector.impl eller vector.hpp.impl för att skilja den från filer som ska kompileras separat.

  • Implementera funktionerna direkt i headerfilen, antingen "inline" eller efter klassdeklarationen.

I vector.cpp använder du & istället för && som logiskt OCH. I det här fallet råkar koden fungera eftersom både vänster- och högerled är ett riktiga booleska uttryck, och alltså evalueras till antingen 0 eller 1, men det ska vara &&.

Din kod är inte exception safe, och kan därför läcka minne. Ett exempel är din copy constructor. Du allokerar rätt mängd minne, men skulle sedan ett element kasta ett undantag när det kopieras kommer minnet att läcka.

Vector<T>::operator= kommer att skriva längre än sin buffer om rhs är för lång.

Detta är nog bara temporärt i din kod, men i Vector<T>::insert pekar du om vec till en temporär buffer. Du har dock den "korrekta" koden utkommenterad, vilket får mig att tro att det är temporärt.

Ok! Tack för all feedback! Underbart!

När det gäller exception safe. Ifall ett element kastar ett undantag så verkar det som att programmet avslutas. Borde då inte operativsystemets heaphanterare automatiskt frigöra all minne som programmet tagit upp? Eller finns det tillfällen då exceptions inte avslutar programmet utan bara delar av det?

Visa signatur

Avatarkreds till: http://imgur.com/HOxIL
Alakai säger: Ryssen skrattar. Norrland hembränner på uppdrag av regeringen. Sälar dör i blyförgiftning, fulla och glada. Förvirringen är total. Kungen är nöjd.

Permalänk
Medlem
Skrivet av Mikael_Berglund:

När det gäller exception safe. Ifall ett element kastar ett undantag så verkar det som att programmet avslutas. Borde då inte operativsystemets heaphanterare automatiskt frigöra all minne som programmet tagit upp? Eller finns det tillfällen då exceptions inte avslutar programmet utan bara delar av det?

Om du fångar undantagen, vilket man brukar göra, avslutas inte programmet.

Vector<Socket> v1; try { Vector<Socket> v2 = v1; } catch (const SocketError &e) { cerr << "Socket error: " << e << "\n"; // Minne har nu läckt, men programmet avslutas ej. }

Visa signatur

Vill du ha svar? Citera mig gärna.