-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 上使用 C++11 和 gcc.4.6.3。

原始代码:

    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 中,代码是非法的,因为如果联合包含上述任何一项,编译器就会删除联合的相应成员。所以你的联合没有默认构造函数、复制构造函数、赋值或析构函数。这意味着您不能实例化它,或以任何方式使用它。这意味着 by 所需的默认构造函数A::A(int)不存在,并且当您定义此函数(或任何构造函数A)时,编译器会报错。

如果编译器编译了这样的代码,则意味着编译器没有正确实现新的联合内容,因此您无法使用它。

关于实际发生的情况:我怀疑编译器在复制构造函数中使用按位复制A (而不是拒绝生成它)。 vec.emplace_back(tmp) 使用复制构造函数在vec. 按位复制意味着您最终得到了两个shared_ptr指向同一个对象的 a 实例,但它们的计数均为 1。第一个正确销毁,第二个访问已删除的内存。繁荣。

解决问题的最简单方法是使用 boost::variant(这意味着struct在联合之外的某个地方定义联合,并给它们一个名字)。如果由于某种原因您不能使用 Boost,那么按照您正在做的事情,手动实现相对微不足道。unsigned char token[ sizeof(TokenType) ];在联合本身中,对于每个非 POD 成员,您只有etc.,如果需要,还有一些额外的成员以确保对齐(在大多数处理器上,adouble可以解决问题)。然后,您使用 reinterpret_cast数组的名称来获取指向所需类型的指针,放置 new 来初始化它,并使用显式销毁来破坏它,这与您所做的非常相似。 并且您实现了一个有效的复制构造函数和一个赋值运算符,并且还考虑了类型。

(这并不难。我已经做过一两次了:解析器中的标记,我们从 Excel 获得的建模表等)

于 2013-01-16T17:34:20.790 回答
1

技术问题:

  • 联合(不要),
  • 未初始化,
  • 三法则(不负责复制)

设计问题:

  • 将类型表示为数字。将类型表示为类型。

保留从编写该代码中获得的知识,然后从头开始。

在您发布真正的代码之前(例如swithc,永远不会编译:您发布的不是真正的代码),几乎没有什么可以说的。

于 2013-01-16T17:31:35.460 回答