2

I have encountered this problem and am wondering what its cause is.

My code is as follows:

struct node{
  bool leaf;
  std::string label;
};

//in main
std::vector<node> graph;
graph.reserve(5);

Now, if i try to assign graph[3].leaf = true;, everything works out.

However, if i try to do the same with an object type, like graphA[i].label = "01";, I get a segmentation fault.

If i change the code to

struct node{
  bool leaf;
  std::string * label;
};

And allocate the memory for the string in every instance of node in the vector, I can now assign a value to graphA[i]->label without a problem.

Why is this? Any responses will be appreciated.

4
  • graph.reserve(5); => graph.resize(5); should fix it. You don't need a pointer and new. Commented Oct 31, 2015 at 15:16
  • 1
    try graph.at(3) to get a nicer error message Commented Oct 31, 2015 at 15:17
  • reserve just reserves, your vector still has zero elements Commented Oct 31, 2015 at 15:17
  • @tobi303: If the exception leaves main, there may not be a nice error message. Commented Oct 31, 2015 at 15:33

2 Answers 2

5

Now, if i try to assign graph[3].leaf = true;

You're invoking undefined behavior.

graph has no element at index 3. In fact, it has no elements at all. You only reserved memory for the vector, but didn't add any elements to it.

You can add 5 default-constructed elements using resize:

graph.resize(5);
Sign up to request clarification or add additional context in comments.

Comments

1

Now, if i try to assign graph[3].leaf = true;, everything works out.

It's important to stress that this is a mere coincidence. Nothing works out - you have undefined behaviour because you access graph[3] when graph is empty. It would be much better if the program crashed right away, so that you notice something is wrong.

graph is empty because you confused std::vector's reserve and resize member functions. You don't set the vector's element count to 5, you just ask it to prepare its internally held memory for at least 5 elements in the future. std::vector is even allowed to ignore this request.

When you do graphA[i].label = "01";, you also have undefined behaviour, of course.

So why do the first version and the pointer "fix" (which also invokes undefined behaviour) seem to work fine while the other one crashes? C++ as a programming language does not distinguish between different kinds of undefined behaviour. Anything can happen; you may as well experience situations in which the first crashes and the second one "works out". Such is the nature of undefined behaviour.

What probably happens here in practice is that in the bool and std::string* case, you are coincidentally writing to a memory location your program is allowed to write to, because you are just dealing with a single bool or with a single pointer. In the std::string version, with all of std::string's automatic dynamic memory management happening behind the scenes, more places in memory are involved and so it happens that you hit a forbidden one.

But that's just a very speculative theory. If you really want to know for sure, debug the code and step into each individual operation. But remember that undefined behaviour is always undefined behaviour.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.