【问题标题】:boost::container::flat_multimap crash on OSX/AppleClang in Release mode发布模式下 OSX/AppleClang 上的 boost::container::flat_multimap 崩溃
【发布时间】:2018-08-01 09:32:04
【问题描述】:

我似乎在 Release 模式 (-O3) 的 MacOS/AppleClang 上遇到 boost::container::flat_multimap (Boost 1.66.0) 的问题。我在 Ubuntu 17.10/GCC7.2 和 Oracle Linux/GCC7.2.1 中测试过,问题没有出现。

下面是一个最小可重现的例子。

代码:

#include <iostream>
#include <vector>

#include <boost/container/flat_map.hpp>

using multimap = boost::container::flat_multimap<int *, int>;

int main(int argc, char **argv)
{
    multimap map;
    std::vector<std::pair<int *, int>> key_value_pairs;

    for (int k = 0; k < 2; k++) {
        int * new_int = new int;
        *new_int = k;
        map.emplace(new_int, k);
        key_value_pairs.emplace_back(new_int, k);
    }

    for (auto it = map.begin(); it != map.end();) {
        if (it->first == key_value_pairs[0].first) {
            it = map.erase(it);
        } else {
            ++it;
        }
    }

    // Should only be one map element left (key_value_pairs[1])
    auto it = map.find(key_value_pairs[1].first);
    if (it == map.end()) {
        throw std::logic_error("Could not find key");
    }

    std::cout  << "Success!" << std::endl;
    return EXIT_SUCCESS;
}

Clang 版本

hoc$ clang --version
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

在本例中,我们生成 2 个 int 指针并将它们作为键插入到 boost::container::flat_multimap 中。然后我们遍历映射并通过识别键来删除其中一个条目。随后我们尝试通过key找到未擦除的元素,但有时找不到(有时会触发第31行的std::logic_error)。

我的代码有错误吗?还是容器?

【问题讨论】:

    标签: c++ macos boost


    【解决方案1】:

    我没有看到任何代码实际上/错误/。

    有相当多的代码异味 - 这里的“等效”程序是否显示相同的问题?

    Live On Coliru

    #include <boost/container/flat_map.hpp>
    #include <iostream>
    #include <vector>
    
    using multimap = boost::container::flat_multimap<int *, int>;
    
    int main() {
        int ks[] = { 0, 1 }; // allocation pool outlives map and key_value_pairs
    
        multimap map;
        for (int &k : ks)
            map.emplace(&k, k);
    
        std::vector<multimap::value_type> const key_value_pairs(map.begin(), map.end());
    
        map.erase(key_value_pairs[0].first);
    
        assert(map.size() == 1);
        assert(map.begin()->first == key_value_pairs[1].first);
    
        assert(map.count(&ks[0]) == 0);
        assert(map.count(&ks[1]) == 1);
    }
    

    【讨论】:

    • 是的,这似乎运行良好。但是您使用的擦除重载与我在示例中使用的不同。当我在示例中用 for 循环替换您的 map.erase 时,第一个断言触发。
    • 啊。灯泡。而已。我忘了它不是基于树的地图。更新答案。
    • 我不相信你的解释是正确的。在所有其他映射类型(包括 std::map 和 std::multimap)中,迭代器擦除重载将迭代器返回到擦除后的元素。如果它总是无效,那么在 boost::container::flat_multimap 中返回该迭代器几乎没有理由。在我们的应用程序中不能使用键擦除重载。
    • 不仅如此,它似乎对 AppleClang 上的所有其他优化模式都是正确的,对于所有优化模式的 GCC 也是如此。
    • 嗯。是的。你也有道理。你说得对。然后我的灯泡又灭了。 flat_maplibc++ 的实现中一定存在错误,或者编译器正在生成无效代码。嗯。我没有mac,所以我现在无法重现东西。 (回滚答案)
    猜你喜欢
    • 2016-02-05
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多