在删除时,在shared_ptr上放置new会使seg出错

时间:2013-01-16 16:52:19

标签: c++ c++11 std

编辑解决方案::

事实上,我是否忘记了复制构造函数中的新内容><"

问题:

我有一个奇怪的问题。在尝试了很长的妈妈来源后,我发现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);
}

2 个答案:

答案 0 :(得分:2)

如果您正在使用C ++ 03进行编译,则代码是非法的,因为 C ++ 03不允许使用非平凡的默认构造函数, 复制构造函数,赋值运算符或析构函数 工会。使用C ++ 11,代码是非法的,因为如果是联盟 包含以上任何一项,编译器删除 工会的相应成员。所以你的工会没有违约 构造函数,复制构造函数,赋值或析构函数。哪一个 意味着您可以实例化它,或以任何方式使用它。哪个 表示A::A(int)所需的默认构造函数不存在 存在,编译应该在你定义时抱怨 function(或A的任何构造函数)。

如果编译器编译这样的代码,则意味着编译器 没有正确实现新的联合内容,因此,那样做 你不能使用它。

关于实际发生的事情:我怀疑是 编译器在A的复制构造函数中使用按位复制 (而不是拒绝生成它)。 vec.emplace_back(tmp) 使用复制构造函数在vec中创建新元素。 按位复制意味着您最终得到两个实例 一个shared_ptr指向同一个对象,但两者都指向同一个对象 计数为1.第一个正确地破坏,而且 第二次访问已删除的内存。吊杆。

解决问题的最简单方法是使用 boost::variant(表示在联合中定义struct 在工会之外的某个地方,并给他们一个名字)。如果是的话 某些原因你不能使用Boost,它相对微不足道 按照你正在做的事情手工实施。在 工会本身,你只有unsigned char token[ sizeof(TokenType) ];等,每个非POD成员,有一些 如有必要,增加成员以确保对齐(大多数情况下 处理器,一个double就可以了。然后你用 reinterpret_cast用于获取指针的数组名称 所需类型,初始化它的新位置和显式 毁灭毁灭它,就像你已经完成的那样。 您实现了复制构造函数和赋值 运作的运算符,并考虑类型。

(这并不困难。我已经做过一两次了。因为 解析器中的标记,用于对从Excel中获取的表进行建模, 等)

答案 1 :(得分:1)

技术问题:

  • union(不要),
  • 未初始化,
  • 三人规则(未正确收费)

设计问题:

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

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

在发布真实代码之前,可以说得更有意义(例如swithc永远不会编译:你发布的内容不是真正的代码。)