在pop_back()之后无法访问向量(分段错误)

时间:2015-09-16 02:40:22

标签: c++

我正在编写一个简单的内存数据库。它应该支持transaction,这意味着BEGIN命令会创建一个新块,其中的操作可以被ROLLBACK命令取消。

我正在使用block实现事务vector列表。在BEGIN的情况下,push_back()该事务块中所有键的unordered_set创建了一个新块。这被定义为vector<unordered_set<string>> key_in_blocks

以下是命令的示例。 SET为变量设置值,GET获取变量的值。

BEGIN
SET a 10
GET a       <-- this prints 10
BEGIN
SET a 20
GET a       <-- this prints 20
ROLLBACK
GET a       <-- this prints 10
ROLLBACK    <-- Segmentation Fault here!

首先有一个默认的block,而keys_in_block看起来像[()],here()表示set,[]表示vector

发布BEGIN后,会创建一个新块,SET会向该块添加一个键a,因此keys_in_block = [(), ('a')]

下一个BEGIN&amp; SET部分类似,使keys_in_block看起来像[(), ('a'), ('a')]

现在ROLLBACK取消在最后一个块中完成的操作,keys_in_block应为[(), ('a')],因为它是pop_back()

我认为我的计划在这一点上做了它需要做的事情。

在第二个ROLLBACK上,它会引发分段错误,看起来我根本无法访问keys_in_block变量。

以下是我的代码段。它在无限循环内运行,从用户那里获取命令。

} else if (command == "BEGIN") {
    int num_blocks = keys_in_block.size();
    keys_in_block.resize(num_blocks + 1); //new transaction block
} else if (command == "ROLLBACK") {
    if (keys_in_block.size() <= 1) {
        cout << "NO TRANSACTION" << endl;
    }
    else {
        auto &recent_keys = keys_in_block.back();
        // undo operations for keys in the most recent transaction block
        for (const string &key : recent_keys) {
            //...
            //...    a bunch of operations that undoes what's done
            //...    in the most recent transaction block.
            recent_keys.erase(key); // erase all keys in the last entry in `keys_in_block`.
        }
        auto & aa = keys_in_block; //***Just for testing, not relevant to the program.
                                   //This throws Segmentation Fault on second ROLLBACK.
        keys_in_block.pop_back();  //Pop back the last transaction block.
    }
}

在代码段中,我使用//***标记了引发分段错误的位置。

我添加了该行,因为keys_in_block.pop_back()引发了分段错误,并希望看到它是否仅通过访问它就会抛出seg错误。

对我来说,算法看起来绝对正确,我无法找出问题的原因。

ROLLBACK只有keys_in_blockblock时,{p> pop_back()无法执行,因此SET不会成为问题。

如果您需要$(document).ready(function() { var iArrayValue = 10000000; setInterval(function() { $("#example").sevenSegArray({ digits: 8, value: iArrayValue }); }); }); 命令部分的代码,请告诉我,但我不认为该代码存在问题。

1 个答案:

答案 0 :(得分:1)

  

我注释掉了recent_keys.erase(key);因为那不是必要的,而且有效!!然而,我无法弄清楚原因。

这是您的程序崩溃的原因,因为您在同时迭代容器时删除了该元素。 for (const string &key : recent_keys)循环试图从开始到结束运行,但是你删除循环中的元素,以便迭代器变为无效,因此循环在尝试递增时不能继续并崩溃迭代器。

  

这很奇怪,因为recent_keys只是对向量中最后一个元素的引用,我正在使用erase删除向量中最后一个元素中的元素。你能解释一下发生了什么,以及如何避免犯同样的错误?

recent_keys是对向量的最后一个元素的引用,但是在迭代时不应该删除元素。如果你想避免犯同样的错误,那么再也不要这样做了。

在您的示例中,您可以迭代recent_keys,然后让keys_in_block.pop_back()进行清理。对于其他情况,您可能希望迭代容器并收集元素引用,然后在完成迭代容器后删除这些元素,您可以使用vector&#39; s erase结合{{1}完成这件事。