-1

ソリューションの編集::

実際、コピー コンストラクターのプレースメント new を忘れてしまいました ><"

質問:

奇妙な問題があります。長い momnet の起源を試した後、masi が理解できないことがわかりました。誰かが私に理由を説明できれば。

私のクラス:

class B; //on other file
class A {
   public:
     A(int type) : type(type)
     {
        switch(type)
        {
           case TOKEN:
           {
             for(int i=0;i<4;++i)
                new(&token.h[i].link) shared_ptr<B>; //< init the ptr on the addr (because of union)
           }break;
           case OTHER: {}break;
        }
     }
     ~A()
      {
        switch(type)
        {
            case TOKEN:
            {
             for(int i=0;i<4;++i)
             {
                /*option 1*/ token.h[i].link.~shared_pt<B>(); //< Make seg fault
               /*option 2*/ token.h[i].link.reset(); //< ok
             }
            }break;
            case OTHER: {}break;
         }
        }
      }
   enum {TOKEN=0,OTHER} type;

   union {
       struct {
           double score;
           struct {
               std::shared_ptr<B> link;
               double to_find;
               } h [4];
       }token;

       struct {
          //else
       } other;
   }
};

私のコード:

void f()
{
    vector<A> vec;
    A tmp = A(A::TOKEN);
    vec.emplace_back(tmp);
}

オプション 1: これにより、f を離れるときにエラーが発生します。オプション 2: わかりましたが、~shared_ptr() は呼び出されないため、メモリ リークが発生しますよね?

誰が間違っているかを理解するのに役立つアイデアがあれば。

編集:Ubuntu 12.04x86でgcc.4.6.3でC++ 11を使用しています。

元のコード:

    class stack_token {
        public:
            stack_token();
            stack_token(const stack_token& other);
            stack_token(const int i,Parser::peptide::peak* data); //peak
            stack_token(const int i,const double e,AnalyseurPeptide::stack_token* peak); //aa
            stack_token(const int i); //aa pour boucher un trou
            stack_token(const double score); //HEADER

            ~stack_token();

            stack_token& operator=(const stack_token& other);

            inline stack_token* get_peak_stack_NULL() {
                stack_token* res = aa_token.pt_data;
                aa_token.pt_data=NULL;
                return res;
            };

            void __print__() const;


            enum Type {UNKNOW=-1,AA_TOKEN=0,AA_HOLD_TOKEN,/*AA_LIST,*/PEAK_TOKEN, HEADER_TOKEN} type;

            union {
                struct  {
                    int index;
                    double error;
                    stack_token* pt_data;
                } aa_token;

                struct{
                    double error;
                    stack_token* pt_data;
                    std::vector<int> aa_index;
                } aa_hold_token;

                struct {
                    int index;
                    Parser::peptide::peak* pt_data;
                } peak_token;

                struct {
                    double score;
                    struct {
                        std::shared_ptr<std::list<list_arg> > link;
                        double to_find;
                    } holds [Parser::peptide::SIZE];
                } header_token;
            };
    };

 stack_token::~stack_token()
{
switch(type)
{
    case AA_TOKEN:
    {
       if(aa_token.pt_data != NULL)
            delete aa_token.pt_data;
    }break;

    case AA_HOLD_TOKEN :
    {
        aa_hold_token.aa_index.~vector<int>();
    }break;

    case PEAK_TOKEN : 
    {
    }break;

    case HEADER_TOKEN : 
    {
       for (int i=0;i<Parser::peptide::SIZE;++i)
            header_token.holds[i].link.reset();//~shared_ptr<std::list<list_arg> >();
    }break;

    default : break;
}
};


  stack_token::stack_token()
{
this->type = UNKNOW;
};

stack_token::stack_token(const int i,Parser::peptide::peak* data) //peak
{
this->type=PEAK_TOKEN;
peak_token.index = i;
peak_token.pt_data = data;
};

stack_token::stack_token(const int i,const double e,AnalyseurPeptide::stack_token* peak) //aa
{
this->type=AA_TOKEN;
aa_token.error =e;
aa_token.index = i;
aa_token.pt_data = peak;
};

stack_token::stack_token(const int i)
{
this->type=AA_HOLD_TOKEN;
aa_hold_token.error = 0;
aa_hold_token.pt_data = this;
new(&aa_hold_token.aa_index) vector<int>();
};


stack_token::stack_token(const double score) //HEADER
{
this->type = HEADER_TOKEN;
header_token.score = score;
for (int i=0;i<Parser::peptide::SIZE;++i)
    new (&header_token.holds[i].link) shared_ptr<list<list_arg> >;
#warning "add to_find init"
};

失敗するコード:

void save_stack(const std::list<stack_token*>& search, std::list<std::vector<stack_token> >& res)
{
    vector<AnalyseurPeptide::stack_token> l;
    auto i=search.begin();
    auto end = search.end();

    stack_token tmp = stack_token(0.f); /* if I remove this */
    l.emplace_back(tmp); /* and this, all is ok */

    while(i!=end)
   {
     l.emplace_back(**i); //< fail here
      ++i;
   }
   res.emplace_back(l);
}
4

2 に答える 2

2

C ++ 03でコンパイルしている場合、コードは不正です。C++ 03では、重要なデフォルトコンストラクター、コピーコンストラクター、代入演算子、またはユニオン内のデストラクタを含む型は許可されていないためです。C ++ 11では、コードが不正です。これは、ユニオンに上記のいずれかが含まれている場合、コンパイラーがユニオンの対応するメンバーを削除するためです。したがって、ユニオンにはデフォルトのコンストラクタ、コピーコンストラクタ、代入、またはデストラクタがありません。つまり、インスタンス化することも、何らかの方法で使用することもできません。これは、が必要とするデフォルトのコンストラクターがA::A(int)存在しないこと、およびこの関数(またはのコンストラクターA)を定義するときにコンパイルが文句を言う必要があることを意味します。

コンパイラがそのようなコードをコンパイルする場合、それはコンパイラが新しいユニオンのものを正しく実装していないことを意味し、したがって、それを使用することはできません。

実際に何が起こるかに関して:コンパイラがA (生成を拒否するのではなく)のコピーコンストラクタでビット単位のコピーを使用しているのではないかと思います。 vec.emplace_back(tmp) コピーコンストラクタを使用して、に新しい要素を作成しますvec。ビット単位のコピーとはshared_ptr、同じオブジェクトを指すが、両方とも1のカウントを持つ2つのインスタンスになってしまうことを意味します。最初のインスタンスは正しく破棄され、2番目のインスタンスは削除されたメモリにアクセスします。ブーム。

問題を解決する最も簡単な方法は、を使用することです (つまり、ユニオンの外部のどこかでユニオンboost::variantを定義し、名前を付けることを意味します)。struct何らかの理由でBoostを使用できない場合は、自分が行っていることに沿って、手作業で実装するのは比較的簡単です。ユニオン自体には、unsigned char token[ sizeof(TokenType) ];POD以外のメンバーごとに、アライメントを確保するために必要に応じていくつかの追加メンバーが含まれています(ほとんどのプロセッサでは、aでdoubleうまくいきます)。次に reinterpret_cast、配列の名前を使用して目的の型へのポインターを取得し、新しい配置を使用して初期化し、明示的に破棄して破棄します。 また、機能するコピーコンストラクターと代入演算子を実装し、型も考慮に入れます。

(それほど難しいことではありません。パーサーのトークン、Excelから取得したテーブルのモデリングなど、1〜2回実行しました。)

于 2013-01-16T17:34:20.790 に答える
1

技術的な問題:

  • ユニオン(しない)、
  • 初期化されていない、
  • 3 つのルール (適切にコピーを担当しない)

設計上の問題:

  • 型を数値で表す。型を型として表します。

そのコードを書いて得た知識を保持し、最初からやり直してください。

実際のコードを投稿するまで、意味のあることはほとんど言えません(たとえば、swithc決してコンパイルされない: あなたが投稿したものは実際のコードではありません)。

于 2013-01-16T17:31:35.460 に答える