导致分段错误的简单字符串分配?

时间:2016-12-19 09:20:13

标签: c++ debugging segmentation-fault c++14 ncurses

我通过很多课程跟踪了这个问题,令我感到惊讶的是,这个错误的来源是一个简单的std::string = std::string操作。

我不会发布整个代码,只发布按顺序执行的函数。我仍然认为SO标准的代码太多,但我认为没有其他选择。

一些背景说明:

  • OrderedPair是一个单独的{ int y, int x }文件中的公共结构lib.inc
  • 前导下划线标记在函数头
  • 中声明的变量
  • 尾随下划线标记了一个类成员变量

ncefm.cc - 基本上是主文件

std::vector<std::string> juststring = {"teststring", "another string", "foobar"};
List* list0 = new List(w0_, juststring); // Source of the error

list.cc - 这里调用构造函数List()

只要忽略可选变量,它们就不会被调用

List::List(Frame* const _parent, std::vector<std::string> &_list,
  const OrderedPair &_pos = {0, 0}, const unsigned int &_spacing = 1,
  const unsigned int &_maxsize = 0) {
  pos_ = _pos;
  size_ = _list.size();
  spacing_ = _spacing;
  maxsize_ = _maxsize;
  parent_ = _parent;

  Fill(_list); //Source of the error

  Redraw();

  parent_->AddWidget(this);
}

list.cc - 成员函数Fill()

list_是std :: vector

类型的成员变量
void List::Fill(std::vector<std::string> &_list) {
  for (unsigned int loop = size_; loop < (size_ + _list.size()); loop++) {
    list_.push_back(new Label(parent_, _list[loop], {pos_.y + (loop * spacing_),
      pos_.x}, maxsize_)); // source of the error (the constructor Label() )
  }
}

label.cc - 构造函数Label()在此处调用

Label::Label(Frame* const _parent, std::string &_text,
  const OrderedPair &_pos = {0,0}, const unsigned int &_maxsize = 0) {
  pos_ = _pos;
  maxsize_ = _maxsize;
  parent_ = _parent;

  SetText(_text); // Source of the error

  parent_->AddWidget(this);
}

list.cc - 成员函数SetText()

我们终于来了,错误的来源是......

void Label::SetText(std::string& _text) {
  if (maxsize_ != 0 && _text.length() > maxsize_) _text.resize(maxsize_);
  text_ = _text; // THIS?!
  size_ = text_.length();

  Redraw();
}

如果我只是注释掉这一行,则错误消失,   当然,这会破坏功能。 text_.assign(_text);也不起作用。

label.h - 显示头文件和某些变量text_

的定义
class Label {
private:
  OrderedPair pos_;

  unsigned int size_;
  unsigned int maxsize_;
  std::string text_;
  Frame* parent_;

public:
  Label(Frame* const _parent, std::string &_text, const OrderedPair &_pos,
    const unsigned int &_maxsize);
  ~Label();

  inline const Frame* GetParent();
  inline unsigned int GetSize();

  inline std::string Text();
  void SetText(std::string&);

  void Move(const OrderedPair &_pos);
  void RMove(const OrderedPair &_pos);

  void Redraw();
  void Clear();
};

如果这太乱了,或者您认为您需要有关我的课程的更多信息,请让我在这里添加它们,或者在开发分支here上查看我的GitHub repo(公共)。

3 个答案:

答案 0 :(得分:3)

看起来您正在访问向量范围(_list[loop])之外的元素:

for (unsigned int loop = size_; loop < (size_ + _list.size()); loop++) {
  list_.push_back(new Label(parent_, _list[loop], {pos_.y + (loop * spacing_), pos_.x}, maxsize_));

答案 1 :(得分:3)

for(unsigned int loop = size_; loop&lt;(size_ + _list.size()); loop ++) {     [...] _list [loop] [...] } 您在列表构造函数中将size_设置为_list.size(),这意味着您开始从末尾开始迭代列表,并且_list [loop]超出范围。 你的意思不是吗? for(unsigned int loop = 0; loop&lt; _list.size(); loop ++) {     [...] _list [loop] [...] }

答案 2 :(得分:1)

C ++实现的供应商倾向于花费大量精力来消除标准库实现中的明显缺陷。因此,问题的实际原因是简单的std::string分配的可能性非常小(大约为零)。

几乎可以肯定的是,程序中的某些代码 - 在赋值发生之前执行 - 将表现出未定义的行为。这可能包括从数组的末尾掉落(例如,访问x[3]其中x是一个数组或std::vector少于三个元素),取消引用空指针,使用未初始化的变量

未定义行为的一个重要特性是效果可能不是立即的....只是在随后执行的一些完全不相关的代码中发生崩溃。

这几乎肯定会在您的代码中发生。您需要向后工作 - 从崩溃发生的位置 - 找到实际导致问题的实际先前执行的代码语句(或代码语句)。

这是SO建议提供MCVE的一个原因 - 删除无关代码的过程可以让您找到实际原因。如果没有,那么他们就有机会帮助你......因为你发布的代码实际上表明了问题。在这种情况下你还没有。

在这种情况下,for循环是罪魁祸首,因为它访问容器的更多元素而不是它。

相关问题