user129186
user129186

Reputation: 1238

Interaction of structs with object attributes and std::vector in c++

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.

Upvotes: 2

Views: 116

Answers (2)

Christian Hackl
Christian Hackl

Reputation: 27538

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.

Upvotes: 1

flogram_dev
flogram_dev

Reputation: 42858

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);

Upvotes: 5

Related Questions