多索引容器 multi_index_container

为什么要使用multi_index_container

相信想必大家在实际开发中一定多少会遇到一些的问题,我需要创建一个可以索引的容器,例如map,set 但是无论map还是set 都是单索引的,例如建立一个类,类里有多个成员变量我们都要对应的索引便于查找 例如:

class Ticket
{
public:int ticketHeight;//块高uint256 ticketTxHash;//票hashCAmount ticketPrice;//当前票的票价CBitcoinAddress ticketAddress;//买票的地址Ticket();Ticket(const Ticket& ticket);Ticket(int ticketHeight, uint256 ticketTxHash, CAmount ticketPrice, CBitcoinAddress ticketAddress);void operator=(Ticket & ticket){this->ticketAddress = ticket.ticketAddress;this->ticketHeight = ticket.ticketHeight;this->ticketPrice = ticket.ticketPrice;this->ticketTxHash = ticket.ticketTxHash;}bool operator==(Ticket ticket){if (this->ticketAddress == ticket.ticketAddress &&this->ticketHeight == ticket.ticketHeight &&this->ticketTxHash == ticket.ticketTxHash &&this->ticketPrice == ticket.ticketPrice){return true;}return false;}std::string toString();~Ticket();
private:};

我需要对ticketHeight,ticketTxHash 经行排序索引,如果只是使用map,set构建索引的话,只能对应一种索引,ticketTxHash 或者ticketHeight,而我们需要使用两个map或者set才可以完成对应的需求,那么有没有一种结构可以对应两个排序索引——答案是有的 就是我们要说的 boost库中的 multi_index_container

下面就来说一下 multi_index_container 的基本使用,以及我遇到的坑,希望大家不要踩到;

创建

multi_index_container可以看作加载在内存中的数据库,不多说直接上代码

 struct ticket_tx_hash {};//为排序索引后表建立的表明()struct ticket_height {};typedefboost::multi_index_container<Ticket,   //此处为你要排序的成员类名indexed_by<    //indexed_by<...> 中填写索引规则ordered_unique< //ordered_unique 类比数据库中的主键为唯一索引,ordered默认升序,还有其他顺序下面会做具体描述//tag<...> 指定表名 需要声明即上面的结构体名//BOOST_MULTI_INDEX_MEMBER boost的宏,表示在目标中选取成员作为排序依据 //(Ticket, uint256, ticketTxHash) Ticket:容器成员  uint256:排序依据的类型  ticketTxHash :排序依据tag<ticket_tx_hash>, BOOST_MULTI_INDEX_MEMBER(Ticket, uint256, ticketTxHash)>,ordered_non_unique<//非唯一索引——可与存在多个tag<ticket_height>, BOOST_MULTI_INDEX_MEMBER(Ticket, int, ticketHeight)>>> ticketpool_set;ticketpool_set ticket_pool;

这样就完成了一个多索引容器类型ticketpool_set的建立,接着实例化了一个ticketpool_set类型的ticket_pool

补充1 :排序不止ordered_unique/ordered_non_unique一种,还有hashed_unique,下面是一段比特币mempool代码,以及指定排序规则

    typedef boost::multi_index_container<CTxMemPoolEntry,boost::multi_index::indexed_by<// hashed_unique 按照hash排序boost::multi_index::hashed_unique<mempoolentry_txid, SaltedTxidHasher>,//指定排序规则 CompareTxMemPoolEntryByDescendantScoreboost::multi_index::ordered_non_unique<boost::multi_index::tag<descendant_score>,boost::multi_index::identity<CTxMemPoolEntry>,CompareTxMemPoolEntryByDescendantScore>,。。。。//省略

不同索引的表 以及 迭代器

两种取迭代器的方法(固定格式)

 //index<ticket_tx_hash>指定tag 为 ticket_tx_hash的表的迭代器typedef ticketpool_set::index<ticket_tx_hash>::type::iterator Ticketiter;//index<0> 去上述排序规则中的第一条规则,实际效果和index<ticket_tx_hash>一样,// 规则序号自0 开始//typedef ticketpool_set::index<0>::type::iterator Ticketiter;

取表

//取出规则需要为0的表,
ticketpool_set::index<ticket_tx_hash>::type & ticket_tx_hash_pool = this->ticket_pool.get<0>();
//取出规则需要为ticket_tx_hash的表,
ticketpool_set::index<ticket_tx_hash>::type & ticket_tx_hash_pool = this->ticket_pool.get<ticket_tx_hash>();

补充2: 在迭代的时候迭代器取出来的为const 类型的,需要注意,通过const_cast可以去除const

使用

ticketPool类完整版

class ticketPool
{
public:ticketPool();~ticketPool();struct ticket_tx_hash {};struct ticket_height {};typedefboost::multi_index_container<Ticket,indexed_by<ordered_unique<tag<ticket_tx_hash>, BOOST_MULTI_INDEX_MEMBER(Ticket, uint256, ticketTxHash)>,ordered_non_unique<tag<ticket_height>, BOOST_MULTI_INDEX_MEMBER(Ticket, int, ticketHeight)>>> ticketpool_set;ticketpool_set ticket_pool;typedef ticketpool_set::index<ticket_tx_hash>::type::iterator Ticketiter;//typedef ticketpool_set::index<0>::type::iterator Ticketiter;bool ticketPush(Ticket& ticket);bool ticketDel(Ticket ticket);bool ticketDelByHeight(int height);void print_ticket(){for (Ticketiter ticketiter = this->ticket_pool.get<ticket_tx_hash>().begin(); ticketiter != this->ticket_pool.get<ticket_tx_hash>().end(); ticketiter++){Ticket  ticket = *ticketiter;std::cout << ticket.toString() << std::endl;}std::cout << "------------------------------------------------------------------------" << std::endl;for (ticketpool_set::index<ticket_height>::type::iterator ticketiter = this->ticket_pool.get<ticket_height>().begin(); ticketiter != this->ticket_pool.get<ticket_height>().end(); ticketiter++){Ticket  ticket = *ticketiter;std::cout << ticket.toString() << std::endl;}}//Ticket ticketAt(unsigned int index);private:};
增加(insert)
bool ticketPool::ticketPush(Ticket& ticket)
{this->ticket_pool.insert(ticket);return true;
}

当然插入之后,表会自动按排序规则更新,完全不用担心

删除 (erase)
ticket_tx_hash_pool.erase(ticketiter);

补充3:如果拿原有表直接删除是不行的,因为原表的为const,这里我是取出表之后在经行删除的。完整代码如下

bool ticketPool::ticketDel(Ticket  ticket)
{ticketpool_set::index<ticket_tx_hash>::type & ticket_tx_hash_pool = this->ticket_pool.get<ticket_tx_hash>();for (Ticketiter ticketiter = this->ticket_pool.get<ticket_tx_hash>().begin(); ticketiter != this->ticket_pool.get<ticket_tx_hash>().end(); ticketiter++){//上面说了迭代器取出的是有const属性的,所以(*ticketiter)==ticket,会导致boost编译时出错,也有一部分原因是我重载== 号的时候时没有const属性的原因if (ticket == (*ticketiter)){ticket_tx_hash_pool.erase(ticketiter);return true;}}return false;
}

补充4 : 删除当然也可以删除一段内容(需要排序后的表),内容为两个迭代器之间的所有东西

bool ticketPool::ticketDelByHeight(int height)
{ticketpool_set::index<ticket_height>::type::iterator pend;ticketpool_set::index<ticket_height>::type::iterator pbegin = this->ticket_pool.get<1>().begin();while (pbegin   != this->ticket_pool.get<ticket_height>().end()){if (pbegin->ticketHeight == height){break;}pbegin++;} pend = pbegin;while (pend->ticketHeight ==height && pend!= this->ticket_pool.get<ticket_height>().end()){pend++;}this->ticket_pool.get<ticket_height>().erase(pbegin, pend);return true;
}
修改(replace和modify)

因为我时在写区块链底层代码,所以我的代码里没有修改这个方法,所以就简单介绍一下修改方法。
修改分为两种方法replace和modify(由ordered_index索引器提供)
可以自己去看boost文档boost中文文档链接

查看(find)
CBitcoinAddress a1("qfWkAzh1DqJTtNegiY7sEQteJUPNxKHEER");
icketpool_set::index<ticket_height>::type::iterator it = this->ticket_pool.get<1>().find(a1);

最后附上完整的代码及测试代码和测试结果,需要结合比特币代码看下,如果只是学习使用就够了

// ticketpool.h
#pragma once#include "uint256.h"
#include "base58.h"
#include "amount.h"#include <list>
#include <string>#include "boost/multi_index/identity.hpp"
#include "boost/multi_index/member.hpp"#include "boost/multi_index_container.hpp"
#include "boost/multi_index/ordered_index.hpp"
#include "boost/multi_index/hashed_index.hpp"
#include <boost/multi_index/sequenced_index.hpp>
using boost::multi_index_container;
using namespace boost::multi_index;class Ticket
{
public:int ticketHeight;//块高uint256 ticketTxHash;//票hashCAmount ticketPrice;//当前票的票价CBitcoinAddress ticketAddress;//买票的地址Ticket();Ticket(const Ticket& ticket);Ticket(int ticketHeight, uint256 ticketTxHash, CAmount ticketPrice, CBitcoinAddress ticketAddress);void operator=(Ticket & ticket){this->ticketAddress = ticket.ticketAddress;this->ticketHeight = ticket.ticketHeight;this->ticketPrice = ticket.ticketPrice;this->ticketTxHash = ticket.ticketTxHash;}bool operator==(Ticket ticket){if (this->ticketAddress == ticket.ticketAddress &&this->ticketHeight == ticket.ticketHeight &&this->ticketTxHash == ticket.ticketTxHash &&this->ticketPrice == ticket.ticketPrice){return true;}return false;}std::string toString();~Ticket();
private:};class ticketPool
{
public:ticketPool();~ticketPool();struct ticket_tx_hash {};struct ticket_height {};typedefboost::multi_index_container<Ticket,indexed_by<ordered_unique<tag<ticket_tx_hash>, BOOST_MULTI_INDEX_MEMBER(Ticket, uint256, ticketTxHash)>,ordered_non_unique<tag<ticket_height>, BOOST_MULTI_INDEX_MEMBER(Ticket, int, ticketHeight)>>> ticketpool_set;ticketpool_set ticket_pool;typedef ticketpool_set::index<ticket_tx_hash>::type::iterator Ticketiter;//typedef ticketpool_set::index<0>::type::iterator Ticketiter;bool ticketPush(Ticket& ticket);bool ticketDel(Ticket ticket);bool ticketDelByHeight(int height);void print_ticket(){for (Ticketiter ticketiter = this->ticket_pool.get<ticket_tx_hash>().begin(); ticketiter != this->ticket_pool.get<ticket_tx_hash>().end(); ticketiter++){Ticket  ticket = *ticketiter;std::cout << ticket.toString() << std::endl;}std::cout << "------------------------------------------------------------------------" << std::endl;for (ticketpool_set::index<ticket_height>::type::iterator ticketiter = this->ticket_pool.get<ticket_height>().begin(); ticketiter != this->ticket_pool.get<ticket_height>().end(); ticketiter++){Ticket  ticket = *ticketiter;std::cout << ticket.toString() << std::endl;}}//Ticket ticketAt(unsigned int index);private:};
//ticketpool.cpp#include "ticketpool.h"
#include "tinyformat.h"
Ticket::Ticket()
{
}Ticket::Ticket(const Ticket&  ticket)
{this->ticketAddress = ticket.ticketAddress;this->ticketHeight = ticket.ticketHeight;this->ticketPrice = ticket.ticketPrice;this->ticketTxHash = ticket.ticketTxHash;
}Ticket::Ticket(int ticketHeight, uint256 ticketTxHash, CAmount ticketPrice, CBitcoinAddress ticketAddress)
{this->ticketAddress =ticketAddress;this->ticketHeight = ticketHeight;this->ticketPrice = ticketPrice;this->ticketTxHash = ticketTxHash;}Ticket::~Ticket()
{
}std::string Ticket::toString()
{std::string ticketStr;ticketStr += strprintf("ticket info:\t ticketAddress = %s \t  ticketHeight = %d \t   ticketPrice = %d \t  ticketTxHash = %s \n",this->ticketAddress.ToString(),this->ticketHeight,this->ticketPrice,this->ticketTxHash.ToString());return ticketStr;
}ticketPool::ticketPool()
{
}ticketPool::~ticketPool()
{
}bool ticketPool::ticketPush(Ticket& ticket)
{this->ticket_pool.insert(ticket);return true;
}bool ticketPool::ticketDel(Ticket  ticket)
{ticketpool_set::index<ticket_tx_hash>::type & ticket_tx_hash_pool = this->ticket_pool.get<ticket_tx_hash>();for (Ticketiter ticketiter = this->ticket_pool.get<ticket_tx_hash>().begin(); ticketiter != this->ticket_pool.get<ticket_tx_hash>().end(); ticketiter++){if (ticket == (*ticketiter)){ticket_tx_hash_pool.erase(ticketiter);return true;}}return false;
}bool ticketPool::ticketDelByHeight(int height)
{ticketpool_set::index<ticket_height>::type::iterator pend;ticketpool_set::index<ticket_height>::type::iterator pbegin = this->ticket_pool.get<1>().begin();twhile (pbegin   != this->ticket_pool.get<ticket_height>().end()){if (pbegin->ticketHeight == height){break;}pbegin++;} pend = pbegin;while (pend->ticketHeight ==height && pend!= this->ticket_pool.get<ticket_height>().end()){pend++;}this->ticket_pool.get<ticket_height>().erase(pbegin, pend);return true;
}Ticket ticketPool::ticketAt(unsigned int index)
{Ticketiter  ticketiter = this->ticket_pool.get<ticket_tx_hash>().begin();if (index >= this->ticket_pool.size()  ){throw std::runtime_error("ticket index error");}for (unsigned int i = 0 ; i < index ; i++){ticketiter++;}return *ticketiter;}

#include <stdio.h>
#include <iostream>
#include <primitives/block.h>
#include "ticketpool.h"
#include "base58.h"
int main(int argc, char* argv[])
{printf("hello world!\n");CBitcoinAddress a1("qfWkAzh1DqJTtNegiY7sEQteJUPNxKHEER");CBitcoinAddress a2("qKyMFKqhTAUu6ka9t2nZ1bxYz1bAYfmuVN");CBitcoinAddress a3("qL3VbDUTbtm8MN9ii8Xm5DZe25LvYhxoe1");CBitcoinAddress a4("qMZupjWUQKFJpY63SvPrqz7R791CYUCsFn");CBitcoinAddress a5("qTLkcQALhxsqetNvkwdQ87XeVaeYoWcHx7");CBitcoinAddress a6("qRpj8gKWNHcYN3HjPpi5p8912fntEX6x5p");uint256 u1;u1.SetHex("0x1c2f3fb3ada4973384f3b1e84267fe7e80888a121b14480b74ed708329370deb");uint256 u2;u2.SetHex("0x2c2f3fb3ada4973384f3b1e84267fe7e80888a121b14480b74ed708329370deb"); uint256 u3;u3.SetHex("0x7c2f3fb3ada4973384f3b1e84267fe7e80888a121b14480b74ed708329370deb"); uint256 u4;u4.SetHex("0x4c2f3fb3ada4973384f3b1e84267fe7e80888a121b14480b74ed708329370deb");uint256 u5;u5.SetHex("0x5c2f3fb3ada4973384f3b1e84267fe7e80888a121b14480b74ed708329370deb");uint256 u6;u6.SetHex("0x6c2f3fb3ada4973384f3b1e84267fe7e80888a121b14480b74ed708329370deb");std::cout << "  a   "  << std::endl;Ticket t1(1,u1,1000, a1);std::cout << "  a  " << std::endl;Ticket t2(1, u2, 1000, a2);Ticket t3(2, u3, 1000, a3);Ticket t4(2, u4, 1000, a4);Ticket t5(3, u5, 1000, a5);Ticket t6(2, u6, 1000, a6);std::cout <<"    " <<t1.toString() << std::endl;ticketPool pool;pool.ticketPush(t1);pool.ticketPush(t2);pool.ticketPush(t3);pool.ticketPush(t4);pool.ticketPush(t5);pool.ticketPush(t6);pool.print_ticket();std::cout << " \n   " << pool.ticketAt(2).toString() << std::endl;std::cout << " \n   " << pool.ticketAt(1).toString() << std::endl;std::cout << " \n   " << pool.ticketAt(0).toString() << std::endl;//pool.ticketDel(t4);pool.ticketDelByHeight(2);std::cout << " -------------delete ---------------------  "  << std::endl;pool.print_ticket();return 0;}


boost multi_index_container 多索引容器的使用相关推荐

  1. 多索引表 (1)boost::multi_index多索引容器

    1. 定义 一个名为multi_index_container的类模板,它支持构建容器来维护一个或多个具有不同排序和访问语义的索引. 每一个multi_index都相当于传统数据库的一个数据表(tab ...

  2. boost::detail模块fwd容器的测试程序

    boost::detail模块fwd容器的测试程序 实现功能 C++实现代码 实现功能 boost::detail模块fwd容器的测试程序 C++实现代码 #include <boost/det ...

  3. Boost:基于不同容器的有界缓冲区比较

    Boost:基于不同容器的有界缓冲区比较 实现功能 C++实现代码 实现功能 基于不同容器的有界缓冲区比较 C++实现代码 #include <boost/circular_buffer.hpp ...

  4. Boost学习之指针容器--pointer_container

    有时,我们可能需要一个包含指针的容器.比如存放一些不可拷贝的对象或者想在容器里存放基类以实现多态.尽管我们可以直接定义存放指针的STL容器,不过这样并不方便,我们得处处小心,在清空或删除容器里的元素时 ...

  5. boost any 实现万能容器_全面剖析 C++ Boost 智能指针!| CSDN 博文精选

    作者 | .NY&XX 责编 | 屠敏 出品 | CSDN 博客 为什么要使用智能指针 C++没有提供类似JAVA的垃圾回收机制,因此Boost可以通过智能指针来管理内存避免一些问题.C++继 ...

  6. boost多个关键字索引multi_index_container

    根据不同的索引排序结构体.其中tag的意思是指定一个标记,如果不指定的话默认是从0开始,以下例子展示了这两种情况 代码: [cpp] view plain copy #include <stri ...

  7. 所有的 Boost 库文档的索引

    入门 工具 网站 新闻 社区 常见问题 更多的信息 按字母顺序列出的库 按类别列出的库 算法 破碎的编译器的解决方法 并发编程 容器 正确性和测试 数据结构 特定于域的 函数对象和高阶编程 泛型编程 ...

  8. Boost.MultiIndex 使用序列索引的示例

    Boost.MultiIndex 使用序列索引的示例 实现功能 C++实现代码 实现功能 Boost.MultiIndex 使用序列索引的示例 C++实现代码 #if !defined(NDEBUG) ...

  9. Boost.MultiIndex 使用随机访问索引的示例

    Boost.MultiIndex 使用随机访问索引的示例 实现功能 C++实现代码 实现功能 Boost.MultiIndex 使用随机访问索引的示例 C++实现代码 #if !defined(NDE ...

最新文章

  1. 各位最近找我索要CCNA200-120的资源的同志些
  2. ubuntu上开启SSH服务
  3. PMCAFF微课堂「已结束」| 测试兄弟CEO揭秘如何提高创初团队的产品质量
  4. Win10+vs2013+Caffe静态库配置自己的工程
  5. java replaceall正则表达式_编写高性能Java代码的最佳实践
  6. 深度linux安装好上不了网,Deepin Linux 无法上网
  7. Android@Home与智能家居
  8. Java 程序读取properties文件
  9. 计算机网络知识点1——概述
  10. Tensorflow - 训练中出现 Nan 值
  11. linux free空闲内存用尽,Linux中显示空闲内存空间的free命令的基本用法,linuxfree...
  12. Mysql 锁机制详解
  13. Latex 表格 tabularx自动换行
  14. JS事件绑定的几种方式
  15. 【操作系统的目标和作用】
  16. Android开发 WebSocket
  17. unigui 验证码生成
  18. 使用爬虫下载汽车之家高清大图
  19. 蓝桥杯31天冲刺之二十三 [java]
  20. 创新产品 google glass

热门文章

  1. 用Qt写的平均绩点计算器
  2. firefox apk android,firefox nightly APK
  3. 二进制安全学习:最新指导Pwn环境搭建教程(安装Peda插件Pwn库 IDApro for Mac15)
  4. 014 | JavaWeb物流配货项目源码 | 大学生毕业设计 | 极致技术工厂
  5. 现在很多的APP都有“附近的人“功能,这是哪个知识实现的呢!
  6. jsp日报系统+mysql_工作日报系统软件(运行web程序+说明) 日报管理系统 - 下载 - 搜珍网...
  7. 在软件测试中如何搭建测试环境?
  8. 被传销洗脑是一种怎样的体验
  9. 在GridView中使用FindControl
  10. kafka Java客户端之consumer 流量控制 以及 Rebalance解析