2016-06-27 10 views
0

Ich stehe vor zwei Problemen, während ich versuche, union-like-class mit Mitgliedern zu machen, die nicht-triviale Destruktoren haben. Ein Segmentierungsfehler, den ich nicht verstehen kann und einen nicht-trivialen Destruktor bedingt benennen kann, den ich nicht herausfinden kann.Wie funktioniert die Union-ähnliche Klasse mit nicht-trivialem Member?

#include <iostream> 
#include <string> 

using namespace std; 

class A { 
    struct B { 
     int u; 
     double v; 
     string w; 
    }; 
    union C { 
     B x; 
     unsigned char y; 
     C(int u, double v, const string& w) { 
      x.w = w;// why does it segfault here? 
      x.u = u; 
      x.v = v; 
     } 
     C(unsigned char c) { 
      y = c; 
     } 
     //omitting this complains because string has non-trivial destructor 
     ~C() { 
      // how to call this conditionally based on A::isChar value 
      //x.w.~string(); 
     } 
    } c; 
    bool isChar; 
public: 
    A(unsigned char f) 
    : isChar{true}, c(f) {} 

    A(int g, double h, const string& i) 
    : isChar{false}, c(g, h, i) {} 

    friend ostream& operator<<(ostream& os, const A& a) { 
     if(a.isChar) 
      return os << a.c.y; 
     return os << a.c.x.u << " " << a.c.x.v << " " << a.c.x.w; 
    } 
}; 

int main() { 
    A a1(10, 20.0, "samik"), a2('v'); 
    cout << a1 << " " << a2 << endl; 
    return 0; 
} 

Ich Kompilieren diese mit g++ -g -std=c++14 -pedantic union_class_test.cpp -o union_class_test.out mit gcc 5.3.1. Wie kann ich das richtig umsetzen?

Antwort

1

Das Programm segfaults auf

x.w = w;// why does it segfault here? 

Da x nicht konstruiert wurde, und enthält x.w Müll. Sie müssen sicherstellen, dass der Konstruktor von B zuerst aufgerufen wird.

C(int u, double v, const string& w) : x() 
    { 
     x.w = w;// why does it segfault here? 
     x.u = u; 
     x.v = v; 
    } 

Und um richtig zu zerstören, müssen Sie es in Destruktor A tun. Lassen Sie C :: ~ C leer, und fügen Sie einen Destruktor A.

~A() 
{ 
    if (!isChar) 
    { 
     c.x.w.~string(); 
    } 
} 

Sie auch darauf achten müssen, wird sein, wenn das Kopieren von A, weil manchmal der Destruktor der Zeichenfolge müssen genannt werden, und manchmal wird es nicht . Eine Möglichkeit, dies zu tun wäre, um die Platzierung zu nutzen, um neue this überschrieben werden soll, und kann wie implementiert werden ...

A& operator=(const A& o) 
{ 
    if (this != &o) 
    { 
     this->~A(); 

     if (o.isChar) 
     { 
      new (this) A(o.c.y); 
     } 
     else 
     { 
      new (this) A(o.c.x.u, o.c.x.v, o.c.x.w); 
     } 
    } 

    return *this; 
} 

Und, bewegt sich in ähnlicher Weise umgesetzt werden. Aber ich überlasse das dem Leser als Übung.

+0

Danke für die heads-up über die Kopie und Verschieben von Zuweisungen, ich habe versucht, die Verschiebung zu implementieren, aber es gibt mir Speicherverlust in Valgrind, kann ich meine Frage bearbeiten, um das Code-Segment, das ich für die Verschiebung Zuordnung wenn Sie sind daran interessiert zu klären. – Samik

Verwandte Themen