1

如何管理boost::intrusive::unordered_setwith的存储桶std::vector?以下代码让我做噩梦:

#include <boost/intrusive/unordered_set.hpp>
#include <vector>
#include <cstdint>

namespace BI = boost::intrusive;

struct ValuableData : public BI::unordered_set_base_hook<>
{
    int  x;
    int  y;
    char c;
};

typedef BI::base_hook<BI::unordered_set_base_hook<>> Options;
typedef BI::unordered_bucket<Options>::type     BucketType;
typedef BI::unordered_bucket_ptr<Options>::type BucketPtr;

struct VectorTraits{

    std::vector<BucketType> v;

    BucketPtr bucket_begin(){
        return v.data();
    }

    uint32_t bucket_count() const {
        return v.capacity();
    }
};

struct dumhash{
    uint32_t operator()(const ValuableData &data) const {
        return data.x;
    }
};

struct dumcomp{
    bool operator()(const ValuableData &data, const ValuableData &datb)     const {
    return true;
}
};

typedef BI::unordered_set<ValuableData, 
        BI::hash<dumhash>, 
        BI::equal<dumcomp>,
        BI::bucket_traits<VectorTraits>> MySet;

int main(){

    VectorTraits tr;

    tr.v.reserve(100);
    tr.v.push_back(BucketType()); //.data() may return null is vector is empty.

    MySet set(tr);
    set.rehash(tr);

    return 0;
}

错误消息表示违反const限定符。我的boost版本是 1.73.0,我的编译器 g++ 10.2.0。我必须使用c++17.

boost intrusive 手册提到const_bucket_ptr但没有说明如何达到该类型。我怀疑这是我的错误的来源,请参阅: https ://www.boost.org/doc/libs/1_74_0/doc/html/intrusive/unordered_set_unordered_multiset.html#intrusive.unordered_set_unordered_multiset.custom_bucket_traits

编辑:我用一个更简单的示例替换了我实际使用的以前的代码,您可以在家里完全编译。这是我的完整错误信息:

In file included from include/boost/intrusive/unordered_set.hpp:18,
                 from src/BoostIntrusiveSet.cpp:9:
include/boost/intrusive/hashtable.hpp: In instantiation of 'void boost::intrusive::hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags>::rehash_impl(const bucket_traits&, bool) [with ValueTraits = boost::intrusive::bhtraits<ValuableData, boost::intrusive::slist_node_traits<void*>, boost::intrusive::safe_link, boost::intrusive::dft_tag, 4>; VoidOrKeyOfValue = void; VoidOrKeyHash = dumhash; VoidOrKeyEqual = dumcomp; BucketTraits = VectorTraits; SizeType = long long unsigned int; long long unsigned int BoolFlags = 3; boost::intrusive::hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags>::bucket_traits = VectorTraits]':
include/boost/intrusive/hashtable.hpp:2944:13:   required from 'void boost::intrusive::hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags>::rehash(const bucket_traits&) [with ValueTraits = boost::intrusive::bhtraits<ValuableData, boost::intrusive::slist_node_traits<void*>, boost::intrusive::safe_link, boost::intrusive::dft_tag, 4>; VoidOrKeyOfValue = void; VoidOrKeyHash = dumhash; VoidOrKeyEqual = dumcomp; BucketTraits = VectorTraits; SizeType = long long unsigned int; long long unsigned int BoolFlags = 3; boost::intrusive::hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags>::bucket_traits = VectorTraits]'
src/BoostIntrusiveSet.cpp:64:15:   required from here
include/boost/intrusive/hashtable.hpp:3153:73: error: passing 'const bucket_traits' {aka 'const VectorTraits'} as 'this' argument discards qualifiers [-fpermissive]
 3153 |       const bucket_ptr new_buckets      = new_bucket_traits.bucket_begin();
      |                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
compilation terminated due to -Wfatal-errors.
4

1 回答 1

0

文档指出需要 const 重载bucket_begin()

用户定义的 bucket-traits 必须满足以下接口:

class my_bucket_traits
{
   bucket_ptr        bucket_begin();
   const_bucket_ptr  bucket_begin() const;
   std::size_t bucket_count() const;
};

我不确定为什么您认为可以安全地使存储桶特征拥有存储桶容器。该示例所做的是存储指向存储桶的指针。这解决了以下问题:

  • 存储桶特征可以廉价复制
  • 存储桶的生命周期与特征的副本无关(因为不持有所有权)
  • 桶数据自然不是 const 即使 trait 实例是

定影

在这里应用相同的方法:

住在科利鲁

#include <boost/intrusive/unordered_set.hpp>
#include <vector>
#include <iostream>

namespace BI = boost::intrusive;
struct ValuableData : public BI::unordered_set_base_hook<> {
    int  x = 0;
    int  y = 0;
    char c = 0;
};

using Options    = BI::base_hook<BI::unordered_set_base_hook<> >;
using BucketType = BI::unordered_bucket<Options>::type;
using BucketPtr  = BI::unordered_bucket_ptr<Options>::type;

struct VectorTraits {
    std::vector<BucketType>* v;
    BucketPtr bucket_begin() const { return v->data(); }
    [[nodiscard]] uint32_t bucket_count() const { return v->capacity(); }
};

struct dumhash {
    uint32_t operator()(const ValuableData& data) const { return data.x; }
};

struct dumcomp {
    bool operator()(const ValuableData& data, const ValuableData& datb) const {
        return data.x == datb.x;
    }
};
typedef BI::unordered_set<ValuableData, BI::hash<dumhash>, BI::equal<dumcomp>,
                          BI::bucket_traits<VectorTraits>>
    MySet;

int main() {
    std::vector<BucketType> buckets(13);
    VectorTraits tr { &buckets };

    MySet set(tr);
    set.rehash(tr);

    std::cout << buckets.size() << "\n";
    buckets.resize(57);
    set.rehash(tr);

    std::cout << buckets.size() << "\n";
}

印刷

13
57
于 2020-11-16T17:00:20.823 回答