[英]Segmentation fault when trying to push_back to a std::vector
我有一个Token
类,其结构如下:
class Token {
public:
void* value;
token_type type; // enum to know which type of data is it storing inside value
unsigned int line;
Token() = default;
Token(void* new_value, token_type new_type):
value(new_value), type(new_type)
{}
~Token() {
//free the memory occupied by the object pointed to by value based on it's type
//this also handles the case of the Token being an instantiation of Statement
}
};
然后是类声明:
class Statement: public Token {
public:
std::vector<Token*>* list;
unsigned int lenght = 0;
Statement() {
list = new std::vector<Token*>;
Token((void*) list, statement);
}
};
基本上,在创建Statement时,内部令牌知道它持有一个语句,因为有一个特定的token_type
类型。 内部令牌在析构函数中对向量进行清理,因此它必须在其value
属性中有一个指向该向量的指针,但是我们在Statement中也有一个指针的副本,所以我们不需要从void*
to std::vector<Token>*
每次;
现在,我想要做的是:
std::string* value = new std::string("Sample text");
Token* to_be_pushed = new Token((void*) value, string); //the object pointed to by value will be deleted in this Token's destructor
Statement* new_statement = new Statement;
new_statement->list->push_back(to_be_pushed);
delete new_statement; //Token destructor gets called; It knows it's a statement,
//so it knows value is pointing to a std::vector<Token*> object, and it deletes each pointer in that vector and then the vector itself
然而,问题是我在new_statement->list
结尾处推送to_be_pushed
的行上遇到Segmentation fault错误。
我已经尝试将这一行分成两部分,我知道问题是当我调用list->push_back
,而不是在访问new_statement->list
。
这是我从gdb得到的回溯:
#0 0xb6e51410 in memmove ()
from /system/lib/libc.so
#1 0x2a0066f8 in std::__copy_move<true, true, std::random_access_iterator_tag>::__copy_m<Token*>
(__first=0x2a0198d0, __last=0x0,
__result=0x2a019908)
at /data/data/com.termux/files/usr/include/bits/stl_algobase.h:378
#2 0x2a006640 in std::__copy_move_a<true, Token**, Token**> (__first=0x2a0198d0, __last=0x0,
__result=0x2a019908)
at /data/data/com.termux/files/usr/include/bits/stl_algobase.h:395
#3 0x2a007070 in std::__copy_move_a2<true, Token**, Token**> (__first=0x2a0198d0, __last=0x0,
__result=0x2a019908)
at /data/data/com.termux/files/usr/include/bits/stl_algobase.h:432
#4 0x2a007010 in std::copy<std::move_iterator<Token**>, Token**> (__first=..., __last=...,
__result=0x2a019908)
at /data/data/com.termux/files/usr/include/bits/stl_algobase.h:464
#5 0x2a006fb0 in std::__uninitialized_copy<true>::__uninit_copy<std::move_iterator<Token**>, Token**> (__first=..., __last=...,
__result=0x2a019908)
at /data/data/com.termux/files/usr/include/bits/stl_uninitialized.h:93
#6 0x2a006f70 in std::uninitialized_copy<std::move_iterator<Token**>, Token**> (__first=...,
__last=..., __result=0x2a019908)
at /data/data/com.termux/files/usr/include/bits/stl_uninitialized.h:123
#7 0x2a006eec in std::__uninitialized_copy_a<std::move_iterator<Token**>, Token**, Token*> (
__first=..., __last=...,
__result=0x2a019908)
at /data/data/com.termux/files/usr/include/bits/stl_uninitialized.h:279
#8 0x2a006dc0 in std::__uninitialized_move_if_noexcept_a<Token**, Token**, std::allocator<Token*> > (__first=0x2a0198d0, __last=0x0,
__result=0x2a019908, __alloc=...)
at /data/data/com.termux/files/usr/include/bits/stl_uninitialized.h:300
#9 0x2a007264 in std::vector<Token*, std::allocator<Token*> >::_M_emplace_back_aux<Token* const&> (this=0x2a019908,
__args=@0x2a0198e8: 0x2a0198d0)
at /data/data/com.termux/files/usr/include/bits/vector.tcc:457
#10 0x2a005b70 in std::vector<Token*, std::allocator<Token*> >::push_back (this=0x2a019908,
__x=@0x2a0198e8: 0x2a0198d0)
at /data/data/com.termux/files/usr/include/bits/stl_vector.h:1049
为什么会这样? 我究竟做错了什么? 这是我发布的错误代码吗?
Token((void*) list, statement);
您期望这可以调用超类的构造函数。 这不会调用构造函数。 所有这一切都是构造一个临时对象,然后立即被销毁。 调用超类的构造函数的唯一方法是在子类的初始化部分:
Statement() : Token(...)
但是在您的情况下,您需要在调用超类的构造函数之前初始化子类,即其list
成员。 这不容易做到。 尽管存在各种方法,但这实际上是这种类层次结构的基本设计缺陷的症状。
您有两种选择:
重新实现您的类层次结构。 你的课程设计方式从根本上说是错误的。 正确设计的C ++代码永远不需要做像铸造到void *
这样的技巧。
在Statement
的构造函数的主体中手动初始化Token
。 使用Token
的默认构造函数,然后在Statement
的构造函数体中修复它。
但是,即使您尝试使用#2方法,您也可能会在以后发现其他问题,特别是:您的Statement
类违反了Rule of Three 。 这几乎可以确保导致许多难以追踪的错误。
这里正确的答案是退后一步,并完全重新设计您的类层次结构。 并且摆脱new
分配以支持正确使用C ++库容器也是一个优点。
有许多方法可以重新设计此类层次结构,如果没有其他信息,则无法建议正确的类设计。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.