开发者

strange behavior with stl containers and pointers

开发者 https://www.devze.com 2023-03-07 23:58 出处:网络
I don\'t understand why the following does not work: queue<int*> q; int counter = 1; for (int i = 0; i < 3; i++) {

I don't understand why the following does not work:

queue<int*> q;

int counter = 1;
for (int i = 0; i < 3; i++) {
    int a[1] = {counter};
    q.push(a);
    counter++;
}

while (!q.empty()) {
    int *top = q.front();
    q.pop();

    cout << top[0] << endl;
}

It should print out: 1 2 3, but instead 3 3 3 开发者_开发问答is printed out. This is because the pointers in the queue are all the same after each run through the loop. Why does that happen?


You are storing pointers to local variables and using those pointers after the local variables they point to have gone out of scope.

In other words: you are invoking Undefined Behavior.

Result: It should not print out "1 2 3". It doesn't have to do anything and is allowed to do whatever it likes. "3 3 3" seems reasonable to me, as it is also allowed to crash.


int a[1] = {counter};
q.push(a);

Not correct. It invokes undefined behvaiour, as a doesn't exist outside the curly braces (the for-loop block). Even if it were well-defined, your code has another problem, all the items in queue is same, as a (the same memory) gets used repeatedly in the loop.

The solution is this:

int *a = new int[1];
a[0] = counter;
q.push(a);

If you do so, then you've to deallocate the memory yourself, of course.


But I'm wondering if every item in queue is just one int,then why not use the following:

queue<int> q;

for (int i = 0; i < 3; i++) 
{
  q.push(counter);
  counter++;
}

Or if you really want array, then why not use std::queue<std::vector<int> > as :

std::queue<std::vector<int> > q;

for (int i = 0; i < 3; i++) 
{
  std::vector<int> v;
  v.push_back(counter);
  q.push(v); //dont worry - a copy of the vector is being pushed!
  counter++;
}

In this way, you don't have to deal with raw pointers. You don't have to allocate or deallocate memory yourself which in my opinion is a safe approach!


You have undefined behavior, since your declaration of a goes out of scope at the end of the loop where you're pushing it into the queue.

What's probably happening is that the memory location of a gets reused each time through, but there are absolutely no guarantees. You might get a different output next time you run it, or you might get a crash, or demons may fly out of your nostrils.


If you insist on using pointers to integers, the following code does what you want:

#include <queue>
#include <iostream>

int main()
{
  std::queue<int*> q;

  int counter = 1;
  for (int i = 0; i < 3; i++) {
    int* a = new int;
    *a = counter;
    q.push(a);
    counter++;
  }

  while (!q.empty()) {
    int *top = q.front();
    q.pop();

    std::cout << *top << std::endl;
    delete top;
  }

  return 0;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号