2017-04-13 4 views
0

Ich habe auf einige Schul Problem gearbeitet und ich, wo ich der Speicherzuweisung kümmerten im operator>> jedoch andere Lösung sah, so habe ich etwas über hier verwirrt .. Die operator>> funktioniert gut, wenn zusammengestellt und gibt gute Ausgaben, aber ich verstehe nicht, warum hier ist der Code .. (Warum ich verwirrt wurde unter dem Code ist)dynamische Speicherzuweisung und Eingang (Strom) Operator C++

class Some 
    { 
    protected: 
     char *name; 
     int price; 
     int anything; 
    public: 
     Some(const char *name="", const int anything=0, const int price=0) 
     { 
      this->name=new char[strlen(name)+1]; 
      strcpy(this->name, name); 
      this->anything = anything; 
      this->price=price; 
     } 
     ~Some() { delete [] name; } 
     friend istream &operator>>(istream &in, Some &i) 
     { 
      return in>>i.name>>i.anything>>i.price; 
     } 
     void print(){ 
      cout << name << " " << anything << " " << price; 
     } 
    }; 

Haupt

int main() { 
    // your code goes here 
    Some n; 
    cin >> n; 
    n.print(); 
    return 0; 
} 

So mit Some n wir haben ein Objekt erstellt, aber der Konstruktor hat Speicher für nur 1 Zeichen zugewiesen, korrigiere mich, wenn ich falsch liege (und setze einige Standardwerte). Danach verwenden wir die >> operator, um ein Objekt des Typs Some einzugeben, jedoch ist nur ein Zeichen für die name reserviert und wir können so viel eingeben, wie wir wollen .. Hier ist die kompilierte Version mit einigen Eingaben Compiled Code. Wo liege ich falsch in meinem Denken? Oder das sollte nicht gemacht werden. Vielen Dank !!

Ps wir nicht benutzen Bibliotheken erlaubt die Pflege der Zuordnung nehmen ..

+0

Ihre Klasse verletzt die Regel der Drei. Das Eingeben von Daten beliebiger Länge in ein Char-Array ist ein schweres Problem ... – aschepler

+1

Sie haben Recht. Dieser Code ist (fürchterlich) kaputt. –

+0

@aschepler Ja, ich weiß, aber das ist nur ein Teil der Klasse, weil ich keine großen Blöcke von Code, die nicht mit meiner Frage verbunden sind. –

Antwort

2

Ein Pufferüberlauf (das ist, was Sie tun, wenn Sie Platz für einen einzelnen char zuweisen, aber das Schreiben weit über es mit Ihrem Aufruf an std::cin >> i.name) gilt als undefiniertes Verhalten in C++. Dies bedeutet, dass Compiler praktisch alles als Reaktion darauf ausführen können, auch wenn es sich um nichts anderes oder um einen Wahnsinn handelt.

In der Praxis bedeutet dies, dass manchmal, wird Ihr Code einwandfrei funktionieren, ohne Probleme ...., bis Sie an einem anderen Tag zu einem anderen Compiler oder Test verschieben oder hatten an diesem Morgen eine andere Art von Kaffee, An diesem Punkt bricht der Code. Was sollte sein passiert ist, dass Ihr Code sollte eine Segmentation Fault (oder in Windows, eine Zugriffsverletzung) aus diesem Code zu werfen, aber meine Vermutung (und ich möchte betonen, dass dies ein rate) ist das Der Aufruf auf Betriebssystemebene, der für das Zuordnen von name verantwortlich ist, belegt Speicher von früher auf einer Speicherseite und Ihre Schreibvorgänge in nicht zugeordnetem Speicher finden gültigen Speicherbereich in dem Rest der Speicherseite.

Offensichtlich sollten Sie sich nicht auf diese Art von Verhalten verlassen. Laut Ihrem Beitrag dürfen Sie kein automatisches Speicherzuweisungsschema wie std::vector<char> oder (die offensichtlich richtige Wahl) std::string verwenden. Dies ist wahrscheinlich, weil Ihr Professor ein Idiot ist, der Ihnen schreckliche Designprinzipien lehrt, weil sie ein seniler alter Narr sind, der seit Jahren aus der Industrie heraus ist und nicht verstanden hat, wie modernes C++ verwendet wird und soll versucht, Ihnen beizubringen, wie man manuelle Speicherzuweisung vornimmt. Aus irgendeinem Grund. Daher müssen Sie Code schreiben, um damit umzugehen.

Das Dokument Paul McKenzie in den Kommentaren (auch here) verbunden ist ein guter Anfang, das zu tun. Seite 3 ist der relevante Code.

Alternativ, wenn Ihr Professor ein plötzlicher Ausbruch von Vernunft hat ihre Meinung ändert, würde der korrigierte Code wie folgt aussehen:

class Some 
{ 
protected: 
    std::string name; 
    int price; 
    int anything; 
public: 
    //Passing by value means an optimization opportunity. We can move-construct name 
    //instead of copying it. 
    Some(std::string name = "", const int anything=0, const int price=0) : 
    //We'll use a member-initialization list to initialize everything. Saves space 
    //and saves a few CPU cycles as well! 
    name(std::move(name)), anything(anything), price(price) 
    {} 

    //We don't need to declare the destructor anymore, because name's memory is automatically 
    //managed! 
    //~Some() {} 

    //this code doesn't need to change. 
    friend std::istream &operator>>(std::istream &in, Some &i) 
    { 
     return in >> i.name >> i.anything >> i.price; 
    } 

    //This doesn't technically *need* to change, but we can do better. 
    //void print(){ 
     //cout << name << " " << anything << " " << price; 
    //} 

    friend std::ostream & operator<<(std::ostream & out, Some const& i) { 
     out << i.name << ' ' << i.anything << ' ' << i.price; 
    } 
}; 
+0

Vielen Dank für die breite Erklärung (und den Humor (was die Wahrheit ist) in Ihrer Antwort implementiert) .. Ich werde versuchen, das gepostete Dokument zu verstehen und String sicher verwenden !! P.s Danke für die Betonung, dass die Initialisierung des Elements spart einige Zyklen (hasste es den ganzen Tag lang) –

+0

isnt 'std :: string' aus einer Bibliothek und kümmert sich um die Zuordnung? – user463035818

+0

@MathNewbie imho lernen, wie einfach es ist, iostreams zu benutzen, ist das erste, was man über C++ lernen sollte, aber ich fürchte, dein Professor ist so alt, dass er keine nette Lösung akzeptiert, aber auf manueller Gedächtnisverwaltung besteht Coder versucht dies zu vermeiden, wann immer es möglich ist. – user463035818

1

Sie richtig über das Problem nachzudenken.

Die Lösung für das Problem besteht darin, die Länge der Zeichenfolge in die Ausgabedatei zu schreiben und dann die Zeichen der Zeichenfolge zu schreiben.

Angenommen, Sie haben Objekt mit:

name = "First Last" 
price = 15 
anything = 0 

Wenn das Objekt geschrieben wird, müssen Sie haben:

10 First Last 0 15 

in der Datei.

Das gibt Ihnen genügend Informationen über das Objekt, damit Sie es aus der Datei zurücklesen können.

istream &operator>>(istream &in, Some &i) 
{ 
    size_t len; 

    // Read the length of name 
    in >> len; 

    // Allocate memory for name. 
    char* name = new char[len+1]; 

    // Read the name. 
    // Discard the whitespace first. 
    in.ignore(); 
    in.read(name, len); 

    // Now read anything and price 
    in >> i.anything >> i.price; 

    // Release memory held by i.name before using memory allocated 
    // in this function 
    delete [] i.name; 
    i.name = name; 

    return in; 
} 

Die Funktion ein Objekt vom Typ Some in eine Datei zu schreiben, hat die Funktion spiegeln sie aus der Datei wieder zu lesen.

std::ostream& operator<<(std::ostream& out, Some const& i) 
{ 
    out << strlen(i.name) << " "; 
    out.write(i.name, strlen(i.name); 
    return out << " " << i.anything << " " << i.price   
} 
+2

Dies könnte das Problem einfacher lösen, ohne auf 'char'-by-char'-Hacks zurückzugreifen, aber aus der Problembeschreibung geht nicht hervor, dass das OP das Format der Eingabe ändern darf Daten. Wenn von ihrem Programm erwartet wird, dass es eine Textdatei liest, die von ihrem Professor bereitgestellt wird, wird diese Lösung ihnen nicht helfen. – Xirema

+0

@ Xirema, das ist wahr. –

Verwandte Themen