为什么 bitset 会抛出 out_of_range 错误?

如何解决为什么 bitset 会抛出 out_of_range 错误?

我正在借助 C++ 中的位集实现布隆过滤器,以找出恶意 URL。 我有一个 100 位的位集和一个简单的哈希函数。但我仍然收到此错误。

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define m 100
#define k 1

ll hash1(string str)
{   
    ll value=0;
    for(ll i=0;i<str.size();i++)
    {
        value=(value+str[i])%m;
    }
    return value;
}

int main(int argc,char *argv[])
{   
    vector<bitset<m>>v(1);
    ifstream fin;
    fin.open(argv[1]);

    string line;
    string temp;
    while(getline(fin,line))
    {   
        vector<string>row;
        stringstream s(line);
        string word;
        while(getline(s,word,','))
        {
            row.push_back(word);
        }
        if(row.size()!=2) continue;
        for(ll i=0;i<k;i++)
        {
            if(row[1]=="bad")
            {   
                v[0].set(hash1(row[0]));
                cout<<row[0]<<" inserted into bloom filter\n";
            }
        }
        row.clear();
    }
    //Now bitset contains all the malicious urls
    //Generating validation dataset
    fin.clear();
    fin.seekg(0);

    vector<vector<string>>validation;
        
    while(getline(fin,line))
    {
        vector<string>row;
        
        ll x=rand()%10;
        if(x>0) continue;
        
        string word;
        stringstream s(line);
        while(getline(s,'))
        {
            row.push_back(word);
        }
        validation.push_back(row);
        row.clear();
    }

    for(ll i=0;i<validation.size();i++)
    {   
        if(v[0].test(hash1(validation[i][0])))
        { 
            if(validation[i][1]=="bad")
            {
                cout<<i+1<<" : True Positive\n";
            }
            else
            {
                cout<<i+1<<" : False Positive\n";
            }
        }
        else 
        {
            cout<<i+1<<" : True Negative\n";
        }
    }
    return 0;
}

错误是:- 抛出“std::out_of_range”实例后调用终止 what(): bitset::set: __position (即 18446744073709551587) >= _Nb (即 100) 中止(核心转储)

数据集包含 2 列即。网址和好/坏。

这是数据集的链接。 https://www.kaggle.com/antonyj453/urldataset

解决方法

仔细阅读后,我认为原因可能是签名字符。如果 涉及到签名字符,

for (char i : str) {
    value = (value + i) % m;
}

可能导致负散列。然而,这实际上不太可能 发生,因为 url 通常不包含高 ascii(确实你会期望 他们的IDNA encoded version 要在列表中)。

快速检查发现列表中有 70 个这样的域

xn---21-6cdxogafsegjgafgrkj4opcf2a.xn--p1ai/images/aaa/,bad
xn--cafsolo-dya.de/media/header/A.php,bad
xn--b1afpdqbb8d.xn--p1ai/web/data/mail/-/aaaaa/Made.htm,bad
xn-----6kcbb3dhfdcijbv8e2b.xn--p1ai/libraries/openid/Auth/OpenID/sec/RBI/index/index.htm,bad

如果情况并非如此,则其他 正在抛出 out_of_range。 没有什么 / 应该 / 因为 operator[] 不会根据 标准。

但是,也许某些实现会在 Debug 版本中进行边界检查(看 在 MSVC 中,他们默认启用了所有方式的迭代器调试 调试构建,所以也许这也是?)。

具有讽刺意味的是,您可以自己使用一些边界检查,例如这里:

int main(int argc,char* argv[]) {
    std::vector<std::string_view> const args(argv,argv + argc);
    std::string const filename(args.at(1));

这样你就不会只在命令时调用 Undefined Behaviour 未给出行参数。

行结束

有一个带有行尾的问题。这些文件是 CRLF,所以你解析的方式 列导致最后一列包含 "bad\r",而不是 "bad"

审查/简化

在寻找其他错误的过程中,我简化了代码。它会执行很多 现在好点了。以下是改进建议的概要。

  1. 包括。只包括你需要的东西,真的

    #include <bitset>
    #include <fstream>
    #include <iostream>
    #include <sstream>
    #include <string>
    #include <vector>
    
  2. 不需要奇怪的类型或宏。

    static constexpr size_t m = 100;
    static constexpr size_t k = 1; // unused for now
    
  3. 如前所述,防止签名字符结果:

    static size_t hash1(std::string_view str) {
       size_t value = 0;
       for (unsigned char i : str) {
           value = (value + i) % m;
       }
       return value;
    }
    
  4. 同样如前所述,防止在 分类文本:

    enum goodbad { good,bad,invalid }; // The Good,The Bad and ...
    
    static goodbad to_classification(std::string_view text) {
        if (text == "bad") return bad;
        if (text == "good") return good;
        return invalid;
    }
    
  5. 接下来,一个大的。您解析同一个文件两次。并重复 代码。不要吧。而是有一个解析它的函数,并将它传递给 回调来决定如何处理解析的数据。

    在此期间,让我们停止无处不在的 vector<vector<vector<string> > > 疾病。真的,您知道有多少列,以及它们的含义。 这也大大减少了分配。

    void process_csv(std::string filename,auto callback) {
        std::ifstream fin(filename);
    
        std::stringstream ss;
        for (std::string line; getline(fin,line);) {
            std::string_view row(line);
    
            // eat line end remnants
            row = row.substr(0,row.find_last_not_of("\r\n") + 1);
    
            if (auto comma = row.find_last_of(','); comma + 1) {
                auto url     = row.substr(0,comma);
                auto goodbad = row.substr(comma + 1);
                auto classif = to_classification(goodbad);
    
                if (classif == invalid)
                    std::cerr << "Ignored unclassified line '" << row << "'\n";
                else
                    callback(url,to_classification(goodbad));
            }
        }
    }
    

    仅此而已。请注意我们仅使用 last 逗号进行拆分的关键见解。因为否则你会得到错误的结果,以防 url 包含逗号。

  6. 现在,您可以拼凑主程序:

    int main(int argc,char* argv[]) {
        std::vector const args(argv,argv + argc);
        std::string const filename(args.at(1));
    

    从前面提到的使用命令行参数的安全方法开始,

    std::bitset<m> bloom;
    

    减少冗长vector<vector<> >综合症(并改进名称 - v?!)

  7. 这里是第一个文件读取通道:

    size_t bloom_size = 0;
    process_csv(filename,[&](std::string_view url,goodbad classification) {
            if (classification == bad) {
                bloom_size += 1;
                bloom.set(hash1(url));
                //std::cout << url << " inserted into bloom filter\n";
            }
        });
    

    我认为没有必要(而且很慢)打印所有 bad url,所以 让我们打印它们的数量:

    // Now bitset contains all the malicious urls
    std::cerr << "Bloom filter primed with " << bloom_size << " bad urls\n";
    
  8. 现在验证通过:

    // do a 1 in 10 validation check
    process_csv(filename,[&bloom,line = 0](std::string_view url,goodbad classification) mutable {
            line += 1;
            if (rand() % 10) return; // TODO #include <random>
    
            auto hit      = bloom.test(hash1(url));
            bool expected = (classification == bad);
    
            std::cout << line << ": " << std::boolalpha
                      << (hit == expected)
                      << (hit ? " positive" : " negative") << "\n";
        });
    }
    

现场演示

Live On Coliru

#include <bitset>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

static constexpr size_t m = 100;
//static constexpr size_t k = 1;

static size_t hash1(std::string_view str) {
    size_t value = 0;
    for (unsigned char i : str) {
        value = (value + i) % m;
    }
    return value;
}

enum goodbad { good,The Bad and ...

static goodbad to_classification(std::string_view text) {
    if (text == "bad") return bad;
    if (text == "good") return good;
    return invalid;
}

void process_csv(std::string filename,to_classification(goodbad));
        }
    }
}

int main(int argc,argv + argc);
    std::string const filename(args.at(1));

    std::bitset<m> bloom;

    size_t bloom_size = 0;
    process_csv(filename,goodbad classification) {
        if (classification == bad) {
            bloom_size += 1;
            bloom.set(hash1(url));
        }
    });

    // Now bitset contains all the malicious urls
    std::cerr << "Bloom filter primed with " << bloom_size << " bad urls\n";

    // do a 1 in 10 validation check
    process_csv(filename,goodbad classification) mutable {
            line += 1;
            if (rand() % 10) return;

            auto hit      = bloom.test(hash1(url));
            bool expected = (classification == bad);

            std::cout << line << ":" << std::boolalpha
                      << (hit == expected)
                      << (hit ? " positive" : " negative") << "\n";
        });
}

在 Coliru 上只有不好的数据集适合,所以我们永远不会得到任何积极的

g++ -std=c++2a -O2 -Wall -pedantic -pthread main.cpp
./a.out bad.csv  | cut -d: -f2 | sort | uniq -c | sort -n

印刷品

Ignored unclassified line 'url,label'
Bloom filter primed with 75643 bad urls
Ignored unclassified line 'url,label'
   7602 true positive

在我自己的系统上:

enter image description here

哦,它在 0.4 秒内运行,而不是之前的 3.7 秒。

在解析错误修复后更快:完整集平均为 0.093 秒。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-