use*_*072 4 c++ pointers vector segmentation-fault
我有一个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
}
};
Run Code Online (Sandbox Code Playgroud)
然后是类声明:
class Statement: public Token {
public:
std::vector<Token*>* list;
unsigned int lenght = 0;
Statement() {
list = new std::vector<Token*>;
Token((void*) list, statement);
}
};
Run Code Online (Sandbox Code Playgroud)
Basically, when creating a Statement, the inner Token knows it's holding a statement because there is a specific token_type type for that. The inner Token does the cleanup of the vector in its destructor so it has to have a pointer to that vector in its value attribute, but we also have a copy of that pointer in the Statement so we don't need to do the cast from void* to std::vector<Token>* each time;
Now, what I am trying to do is this:
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
Run Code Online (Sandbox Code Playgroud)
The problem, however, is I am getting a Segmentation fault error on the line where I push to_be_pushed at the end of new_statement->list.
I've tried breaking that line in two pieces, and I know the problem is when I am calling list->push_back, not when accessing new_statement->list.
Here's the backtrace I got from 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
Run Code Online (Sandbox Code Playgroud)
Why is this happening? What am I doing wrong? Is it the code I've posted fault?
Token((void*) list, statement);
Run Code Online (Sandbox Code Playgroud)
You are expecting this to call the superclass's constructor. This does not call the constructor. All this does is construct a temporary object, which then gets immediately destroyed. The only way to call the superclass's constructor is in the initialization section of the subclass:
Statement() : Token(...)
Run Code Online (Sandbox Code Playgroud)
但是,在您的情况下,您需要list在调用超类的构造函数之前初始化子类,即其成员。这并不容易做到。尽管有很多方法可以解决这个问题,但这确实是此类层次结构的基本设计缺陷的症状。
您有两个选择:
重新实现您的类层次结构。你的课程设计方式从根本上是错误的。正确设计的 C++ 代码永远不需要执行诸如转换为void *.
Token在 的构造函数主体中手动初始化Statement。使用 的默认构造函数,然后在的构造函数主体Token中修复它。Statement
然而,即使您尝试第二种方法,您以后也可能会发现其他问题,特别是:您的Statement类违反了“三法则”。这几乎肯定会导致许多难以追踪的错误。
这里正确的答案是退一步,完全重新设计你的类层次结构。摆脱new分配以支持正确使用 C++ 库容器也将是一个优点。
有很多方法可以重新设计这个类层次结构,如果没有额外的信息,就不可能建议正确的类设计。