0

The following piece of code compiles and runs just fine, but I have been reading up on reinterpret_cast and I can't really make out if it's standard compliant and is portable. In my head it should be since we explicitly specify the underlying container of the priority_queue but I haven't been able to get a straight answer so SO-wizards might have some insight into this piece.

What it does is basically create a priority_queue that deals with integers using a vector. It then reinterpret_cast's that queue into a vector-pointer so that the elements of the queue can be iterated over (since priority_queue does not include that functionality itself).

#include <iostream>
#include <vector>
#include <queue>


int main() {
    std::priority_queue< int, std::vector<int> > pq;

    pq.push(100);
    pq.push(32);
    pq.push(1);

    auto o = reinterpret_cast<std::vector<int> *>(&pq);
    for (std::vector<int>::iterator it = (*o).begin(); it != (*o).end(); it++) {
        std::cout << (*it) << std::endl;
    }

    return 0;
}

2 Answers2

2

The standard makes no guarantees about the layout of the std::priority_queue class. If this works on your implementation, it must be because the std::vector is stored at the beginning of the std::priority_queue object, but this certainly cannot be relied upon.

The proper thing to do is write your own variant of std::priority_queue (the <algorithm> header already contains the necessary heap algorithms, such as std::push_heap) or to derive a class from std::priority_queue, which gives you access to the protected member c which refers to the underlying container.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
0

The following piece of code compiles and runs just fine

phew! that was lucky.

but I have been reading up on reinterpret_cast and I can't really make out if it's standard compliant

yes it is

and is portable.

almost never. certainly not the way you're using it. It's one of those 'if you don't know exactly how it works, don't touch it' things.

You can portably reinterpret cast an A* to a void*, and back to an A*... than that's about it (OK, there are a few more use cases, but they are specific and you need to know them before you play with this particular stick of dynamite).

In my head it should be since we explicitly specify the underlying container of the priority_queue but I haven't been able to get a straight answer so SO-wizards might have some insight into this piece.

std::priority_queue is a specific adaptation of the underlying container. Because the correct operation of the queue depends upon you not tampering with the underlying container, the queue's interface deliberately hides it from you.

What it does is basically create a priority_queue that deals with integers using a vector. It then reinterpret_cast's that queue into a vector-pointer so that the elements of the queue can be iterated over (since priority_queue does not include that functionality itself).

What it really does is invoke undefined behaviour which makes it no longer possible to reason about the outcome of any part of your program. If it worked on your environment, that's a shame. Because now you'll be tempted to release it into mine, where it probably won't, or might for a while - while silently polluting my memory until... BOOM! my process core dumps and we're all clueless as to why.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142