1

I've tracked this problem through a lot my classes, and it surprised me, that the source of this error is a simple std::string = std::string operation.

I won't post the whole code, just the functions that are executed in sequence. I still think that there is too much code for SO standards, but I see no other option.

Some context notes:

  • OrderedPair is a public struct { int y, int x } in a separate lib.inc file.
  • Leading underscore marks a variable declared in the function header
  • Trailing underscore marks a class member variable

ncefm.cc -- basically the main file

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

list.cc -- constructor List() is called here

Just ignore the optional variables, they aren't called anyway

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 -- Member function Fill()

list_ is a member variable of type 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 -- constructor Label() is called here

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 -- Member function SetText()

Here we finally are, the source of the error is...

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

  Redraw();
}

If I just comment out this line, the error dissapears, of course, that defeats the functionality. text_.assign(_text); doesn't work either.

label.h -- To show the header file and definition of some variable 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();
};

If this is too messy, or you think you need more information about my classes, ask me to add them here, or look at my GitHub repo (public) on the dev branch here.

mrflash818
  • 930
  • 13
  • 24
niraami
  • 646
  • 8
  • 18
  • 2
    Can you give us minimal, complete, compilable code that we can use to replicate the problem? – David Schwartz Dec 19 '16 at 09:23
  • @DavidSchwartz In all of my SO questions, I try to do that, but what am I supposed to do, when I don't know how to replicate it outside of this scenario? In this case, the problem was absolutely somewhere else than the error message pointed me to - It didn't error when it went out of bounds of the vector... – niraami Dec 19 '16 at 10:38
  • 1
    @areuz `_list.at(loop)` instead of `_list[loop]` would have identified the problem immediately. Also, it isn't a good idea to name your variables with leading underscores, like `_list`. – PaulMcKenzie Dec 19 '16 at 10:41
  • @PaulMcKenzie Hmm, good to know, I will try that and maybe use that from now on. Why is it not good in your opinion? I use it, because it's the opposite of a member variable, which has a trailing underscore. – niraami Dec 19 '16 at 10:45
  • Use `at()` as a sanity check to ensure you're not going out of bounds. Once you're sure of this, then change back to `[ ]`. As to the leading underscore, names with leading underscores are reserved for the compiler's implementation. I know there are rules where it is "safe" to use leading underscores, but they're too hard for me to remember, so I never use leading underscores. A search on SO will direct you to threads that explain this. – PaulMcKenzie Dec 19 '16 at 10:46
  • [Here is a link to the rules for leading underscores](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – PaulMcKenzie Dec 19 '16 at 10:51
  • @PaulMcKenzie Hmm... I see. Alright I might have to change my habits. – niraami Dec 19 '16 at 10:57
  • @areuz Well that's the point of doing it. When you tried to strip the program down, at some point you would have removed the actual cause of the problem, and when that made the problem go away, you would have probably solved it yourself. – David Schwartz Dec 19 '16 at 18:22

3 Answers3

3

Looks like you are accessing elements outside vector's range (_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_));
jimvonmoon
  • 342
  • 3
  • 12
3
for (unsigned int loop = size_; loop < (size_ + _list.size()); loop++) 
{
    [...] _list[loop] [...]
}

You set size_ to _list.size() in the list constructor, so it means you start iterating your list from the end, and _list[loop] is out of bounds.

Didn't you mean this instead ?

for (unsigned int loop = 0 ; loop < _list.size() ; loop++) 
{
    [...] _list[loop] [...]
}
dydil
  • 949
  • 7
  • 20
1

Vendors of C++ implementations tend to apply a lot of effort to eliminating obvious flaws from their implementation of the standard library. So the odds of the actual cause of your problem being a simple std::string assignment are vanishingly small (approximately zero).

What will almost certainly be happening is that some code in your program - executed BEFORE the assignment occurs - will be exhibiting undefined behaviour. This might include falling off the end of an array (e.g. accessing x[3] where x is an array or a std::vector with less than three elements), dereferencing a null pointer, using an uninitialised variable.

One of the quainter properties of undefined behaviour is that the effect may not be immediate .... only for a crash to occur in some completely unrelated code that is subsequently executed.

This is almost certainly happening in your code. You need to work backward - from the point where the crash occurs - to find the actual previously executed code statement (or code statements) that actually caused the problem.

This is one reason that advice on SO is to provide an MCVE - the process of cutting out extraneous code can allow you to find the actual cause. If it doesn't, them someone has a fighting chance of helping you ... because you post code that actually exhibits the problem. Which you haven't in this case.

In this case, the for loop is the culprit, since it is accessing more elements of a container than it has.

Peter
  • 35,646
  • 4
  • 32
  • 74