2016-06-27 1 views
0

私はデリバターの仕事が些細なメンバーとの組合様クラスを作成しようとする際に2つの問題に直面しています。私が理解できないセグメンテーションフォールトと、私が理解できない条件付きで非自明なデストラクタを呼び出す方法。非自明のメンバでクラスのような共用体を正しく動作させるにはどうすればいいですか?

#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; 
} 

私は、GCC 5.3.1でg++ -g -std=c++14 -pedantic union_class_test.cpp -o union_class_test.outでこれをコンパイルしています。これを正しく実装するには?

答えて

1

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

上のプログラムセグメンテーション違反xが構築されていない、とx.wはゴミが含まれているため。 Bのコンストラクタが最初に呼び出されるようにする必要があります。

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

、正しく破壊するためには、あなたはAのデストラクタでそれを行う必要があります。 〜Cが空:: Cのままにして、あなたはまた、Aさんをコピーするときに時々、文字列のデストラクタが呼び出される必要があるので、注意する必要があります。A.

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

にデストラクタを追加し、時にはそれはしません。そうするための一つの方法は、thisを上書きする新しい配置を使用するだろう、と

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

...のように実装することが可能と、移動も同様に実装されます。しかし、私はそれを読者に練習として残しておきます。

+0

私は移動割り当てを実装しようとしましたが、valgrindでメモリリークが発生しました。移動割り当てに使用しているコードセグメントを含めるように質問を編集できます。明確にすることに興味があります。 – Samik

関連する問題