【问题标题】:Simple string assignment causing a segmentation fault?导致分段错误的简单字符串分配?
【发布时间】:2016-12-19 09:20:13
【问题描述】:

我在很多课程中都跟踪过这个问题,令我惊讶的是,这个错误的根源是一个简单的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 存储库(公共)。

【问题讨论】:

  • 你能给我们最小的、完整的、可编译的代码,我们可以用它来复制问题吗?
  • @DavidSchwartz 在我所有的 SO 问题中,我都尝试这样做,但是当我不知道如何在这种情况之外复制它时,我应该怎么做?在这种情况下,问题绝对出在错误消息指向我的其他地方 - 当它超出向量范围时没有出错......
  • @areuz _list.at(loop) 而不是 _list[loop] 会立即发现问题。此外,使用前导下划线命名变量也不是一个好主意,例如_list
  • @PaulMcKenzie 嗯,很高兴知道,我会尝试,也许从现在开始使用它。为什么在你看来不好?我使用它,因为它与成员变量相反,成员变量后面带有下划线。
  • 使用at() 作为健全性检查,以确保您不会越界。一旦你确定这一点,然后改回[ ]。至于前导下划线,带有前导下划线的名称是为编译器的实现保留的。我知道有些规则使用前导下划线是“安全的”,但它们对我来说太难记住了,所以我从不使用前导下划线。搜索 SO 将引导您找到解释这一点的线程。

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


【解决方案1】:
for (unsigned int loop = size_; loop < (size_ + _list.size()); loop++) 
{
    [...] _list[loop] [...]
}

您在列表构造函数中将size_ 设置为_list.size(),这意味着您从末尾开始迭代列表,而_list[loop] 超出范围。

你不是说这个吗?

for (unsigned int loop = 0 ; loop < _list.size() ; loop++) 
{
    [...] _list[loop] [...]
}

【讨论】:

    【解决方案2】:

    看起来您正在访问向量范围之外的元素 (_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_));
    

    【讨论】:

      【解决方案3】:

      C++ 实现的供应商往往会付出很多努力来消除标准库实现中的明显缺陷。因此,您的问题的实际原因是简单的std::string 分配的可能性非常小(大约为零)。

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

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

      这几乎肯定会发生在您的代码中。您需要从发生崩溃的那一点开始向后工作,以找到实际导致问题的实际先前执行的代码语句(或多个代码语句)。

      这是关于 SO 的建议是提供 MCVE 的原因之一 - 删除无关代码的过程可以让您找到实际原因。如果不是这样,他们就会有机会帮助您……因为您发布的代码实际上会出现问题。在这种情况下你没有。

      在这种情况下,for 循环是罪魁祸首,因为它访问的容器元素比它拥有的要多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-03-20
        • 1970-01-01
        • 2017-08-02
        • 1970-01-01
        • 1970-01-01
        • 2013-04-11
        • 2015-08-06
        相关资源
        最近更新 更多