使用struct指针的std :: priority_queue时出现意外结果

时间:2014-01-08 00:22:40

标签: c++ c++11 std priority-queue stdvector

我确信代码是非常自我解释的,所以我直截了当地说。如果代码不清楚,请询问更多详细信息。

Foo.h
=====

#include <iostream>

class Foo
{
public:
    virtual ~Foo(){};
    Foo();
    Foo(const int b);
    bool operator<(const Foo&) const;
    friend std::ostream& operator<<(std::ostream&, const Foo&);

    int b;
};

Foo.cpp
=======

#include "Foo.h"

Foo::Foo()
{
}

Foo::Foo(const int b)
{
    this->b = b;
}

bool Foo::operator<(const Foo& other) const
{
    return b < other.b;
}

std::ostream& operator<<(std::ostream& os, const Foo& f)
{
    os << '{' << f.b << '}';
    return os;
}

Bar.h
=====

#include <vector>
#include <queue>
#include "Foo.h"

class Bar
{
    struct FooPp
    {
        Foo f;
        int a;

        FooPp(const Foo&);
        bool operator<(const FooPp&) const;
        friend std::ostream& operator<<(std::ostream& os, const FooPp& fpp)
        {
            os << '[' << fpp.a << "]," << fpp.f;
            return os;
        }
    };

    struct foopp_compare
    {
        bool operator()(const FooPp* pA, const FooPp* pB ) const 
        {
            return *pA < *pB;
        }
    };

public:
    virtual ~Bar(){};
    Bar(const std::vector<Foo>&);

    std::vector<FooPp> vf;
    std::priority_queue<FooPp*, std::vector<FooPp*>, foopp_compare> fq;
};

Bar.cpp
=======

#include "Bar.h"

Bar::FooPp::FooPp(const Foo& f)
{
    this->f = f;
    a = f.b;
}

bool Bar::FooPp::operator<(const FooPp& other) const
{
    return f < other.f;
}

Bar::Bar(const std::vector<Foo>& vf)
{
    for (std::vector<Foo>::const_iterator f = vf.begin();
            f != vf.end();
                ++f)
    {
        this->vf.push_back(*f);
        fq.push(&(this->vf.back()));
    }
}

main.cpp
========

#include <iostream>
#include "Bar.h"

int main()
{
    // Foo
    Foo f1(1);
    Foo f2(6);
    std::vector<Foo> vf;
    vf.push_back(f1);
    vf.push_back(f2);
    // Bar
    Bar b(vf);
    // print b.vf: [1]{1}, [6],{6};
    std::cout << b.vf[0] << '\n';
    std::cout << b.vf[1] << '\n';
    // print the top of the prio_q: [6],{6};
    std::cout << *(b.fq.top()) << '\n';
    // change "a" in b.vf[1] -> [-12],{6}
    b.vf[1].a = -12;
    // print b.vf[1]: [-12],{6};
    std::cout << b.vf[1] << '\n';
    // print the top of the prio_q: [-12],{6};
    std::cout << *(b.fq.top()) << '\n';
    return 0;
}

这就是我所得到的:

./example 
[1],{1}            // OK
[6],{6}            // OK
[1],{135704652}    // ??
[-12],{6}          // OK
[1],{135704652}    // ??

std::vector<FooPp>似乎已正确初始化,但我不明白std::priority_queue发生了什么,应该使用指向std::vector<FooPp>元素的指针进行初始化。怎么了?

顺便说一句..这是Unix机器上那些人的makefile

Makefile
========

CXX      := g++
LD       := g++
CXXFLAGS := -Wall -g -O0 --std=c++0x -I.

SRC := $(shell ls *.cpp)
OBJ := ${SRC:%.cpp=%.o}

.PHONY: clean

example: $(OBJ)
    $(LD) $^ -o $@

clean:
    rm -rf $(OBJ) *~ example

2 个答案:

答案 0 :(得分:2)

每次推送都会修改基础向量vf,并使进程中的所有迭代器(以及从中获取的地址)无效。

我看到解决此问题的最快方法是修改Bar的构造函数:

Bar::Bar(const std::vector<Foo>& vf)
    : vf(vf.begin(), vf.end())
{
    for (std::vector<FooPp>::iterator f = this->vf.begin();
         f != this->vf.end();
         ++f)
    {
        fq.push(&(*f));
    }
}

<强>输出

[1],{1}
[6],{6}
[6],{6}
[-12],{6}
[-12],{6}

还有一个主机我将对此代码做的其他事情(使用初始化程序列表等),但这是关于我能想到的最小的代码更改将为您提供一些的工作原理。

答案 1 :(得分:0)

我认为问题出在这里

Bar::Bar(const std::vector<Foo>& vf)
{
    for (std::vector<Foo>::const_iterator f = vf.begin();
            f != vf.end();
                ++f)
    {
        this->vf.push_back(*f);
        fq.push(&(this->vf.back()));
    }
}

向向量添加新元素时,可以重新分配已用内存。所以这个值&amp;(this-&gt; vf.back())变得无效。