【问题标题】:Boost::geometry query returning indexesBoost::geometry 查询返回索引
【发布时间】:2015-05-07 12:53:47
【问题描述】:

我想上课,它使用boost::geometry::index::rtree 作为空间索引器。仅这个类就应该知道 boost,所以我使用这样的东西:

struct VeryImportantInfo
{
    ...
    float x;
    float y;
}

class Catalogue
{
    ...
public:
    std::vector<std::shared_ptr<VeryImportantInfo> > FindIn(float x1, float x2, float y1, float y2);

protected:
    using point = bg::model::point<float, 2, bg::cs::cartesian>;
    using value = std::pair<point, std::shared_ptr<VeryImportantInfo> >;
    using box = bg::model::box<point>;        

    boost::geometry::index::rtree< value, bgi::quadratic<16> > rtree;
}

std::vector<std::shared_ptr<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
{
    box query_box(point(x1, y1), point(x2, y2));
    ???
}

我不知道如何正确查询(请不要看这个可怕的复制返回的向量,它只是为了举例)。我可以这样做:

std::vector<std::shared_ptr<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
{
    box query_box(point(x1, y1), point(x2, y2));
    std::vector<value> result_s;
    rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));
    std::vector<std::shared_ptr<VeryImportantInfo> > results;
    results.reserve(result_s.size());
    for( auto& p : result_s)
    {
        results.emplace_back(p.second);
    }
    return results;
}

我想知道,我怎样才能摆脱内部副本(不返回副本,results.emplace_back(p.second); - 这个)。因为我可以在result_s 中获得超过 10k 的结果,这将是一种浪费。

谢谢!

【问题讨论】:

    标签: c++ c++11 boost boost-geometry


    【解决方案1】:

    更新评论

    如果一开始担心的是临时向量,那就不要使用一个。您可以使用来自boost::geometry::indexqbegin()/qend()免费功能:

    std::vector<std::shared_ptr<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
    {
        box query_box(point(x1, y1), point(x2, y2));
    
        auto b = bgi::qbegin(rtree, bgi::intersects(query_box)), 
            e = bgi::qend(rtree);
    
        auto range  = boost::make_iterator_range(b, e);
    
        using namespace boost::adaptors;
        return boost::copy_range<std::vector<std::shared_ptr<VeryImportantInfo>>>(
                range | transformed([](value const& p) { return p.second; }));
    }
    

    事实上,如果 rtree 已知是常量,你甚至可以直接返回惰性范围,甚至不分配单个向量。


    原始/旧答案文本如下:


    没有引用计数就不能复制共享指针。

    当然,您可以将 value 对更改为包含对 shared_ptr 的 reference,但是您可以使用原始引用 (std::reference_wrapper) 或 weak_ptr

    std::reference_wrapper&lt;T&gt;

    这是我对原始参考的看法(只需保留您的 重要数据 :)):

    Live On Coliru

    #include <iostream>
    #include <vector>
    
    #include <boost/geometry/geometries/point_xy.hpp>
    #include <boost/geometry/index/rtree.hpp>
    
    namespace bg  = boost::geometry;
    namespace bgi = bg::index;
    
    struct VeryImportantInfo {
        float x;
        float y;
    };
    
    VeryImportantInfo a = { 2, 2 };
    VeryImportantInfo b = { 3, 3 };
    VeryImportantInfo c = { 4, 4 };
    
    class Catalogue
    {
    public:
        Catalogue() {
            rtree.insert(value(point(a.x, a.y), a));
            rtree.insert(value(point(b.x, b.y), b));
            rtree.insert(value(point(c.x, c.y), c));
        }
    
        std::vector<std::reference_wrapper<VeryImportantInfo> > FindIn(float x1, float x2, float y1, float y2);
    
    protected:
        using point = bg::model::point<float, 2, bg::cs::cartesian>;
        using value = std::pair<point, std::reference_wrapper<VeryImportantInfo> >;
        using box   = bg::model::box<point>;
    
        boost::geometry::index::rtree< value, bgi::quadratic<16> > rtree;
    };
    
    std::vector<std::reference_wrapper<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
    {
        box query_box(point(x1, y1), point(x2, y2));
    
        std::vector<value> result_s;
        rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));
    
        std::vector<std::reference_wrapper<VeryImportantInfo> > results;
        results.reserve(result_s.size());
    
        for(auto& p : result_s) {
            results.push_back(p.second);
        }
        return results;
    }
    
    int main() {
        Catalogue cat;
        for (VeryImportantInfo& vii : cat.FindIn(1,2,3,4))
            std::cout << vii.x << ", " << vii.y << "\n";
    }
    

    std::weak_ptr&lt;T&gt;

    这里与weak_ptr&lt;&gt; 相同。有人可能会说这并不能解决太多问题(因为引用计数仍在发生),但至少需要更少的工作。

    Live On Coliru

    #include <iostream>
    #include <memory>
    #include <vector>
    
    #include <boost/geometry/geometries/point_xy.hpp>
    #include <boost/geometry/index/rtree.hpp>
    
    namespace bg  = boost::geometry;
    namespace bgi = bg::index;
    
    struct VeryImportantInfo {
        float x;
        float y;
    };
    
    auto a = std::make_shared<VeryImportantInfo>(VeryImportantInfo{2, 2});
    auto b = std::make_shared<VeryImportantInfo>(VeryImportantInfo{3, 3});
    auto c = std::make_shared<VeryImportantInfo>(VeryImportantInfo{4, 4});
    
    class Catalogue
    {
    public:
        Catalogue() {
            rtree.insert(value(point(a->x, a->y), a));
            rtree.insert(value(point(b->x, b->y), b));
            rtree.insert(value(point(c->x, c->y), c));
        }
    
        std::vector<std::weak_ptr<VeryImportantInfo> > FindIn(float x1, float x2, float y1, float y2);
    
    protected:
        using point = bg::model::point<float, 2, bg::cs::cartesian>;
        using value = std::pair<point, std::shared_ptr<VeryImportantInfo> >;
        using box   = bg::model::box<point>;
    
        boost::geometry::index::rtree< value, bgi::quadratic<16> > rtree;
    };
    
    std::vector<std::weak_ptr<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
    {
        box query_box(point(x1, y1), point(x2, y2));
    
        std::vector<value> result_s;
        rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));
    
        std::vector<std::weak_ptr<VeryImportantInfo> > results;
        results.reserve(result_s.size());
    
        for(auto& p : result_s) {
            results.push_back(p.second);
        }
        return results;
    }
    
    int main() {
        Catalogue cat;
        for (auto& vii_p : cat.FindIn(1,2,3,4))
            if (auto vii = vii_p.lock())
                std::cout << vii->x << ", " << vii->y << "\n";
    }
    

    【讨论】:

    • 真的很不错!但我应该更强调一点:主要问题是 - 我可以在result_s 向量中拥有>10k 个对象,所以这不是引用计数的问题,这个数组的整个副本将是一个很大的浪费。
    • 按原样返回向量?或使用map_values 范围适配器。
    • 如何使用 map_values?
    猜你喜欢
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多