编辑解决方案::
事实上,我是否忘记了复制构造函数中的新内容><"
问题:
我有一个奇怪的问题。在尝试了很长的妈妈来源后,我发现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);
}
答案 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)
技术问题:
设计问题:
保留从编写该代码中获得的知识,并从头开始。
在发布真实代码之前,可以说得更有意义(例如swithc
永远不会编译:你发布的内容不是真正的代码。)