【问题标题】:const inline std::map in header causes heap corruption at exit标头中的 const inline std::map 导致退出时堆损坏
【发布时间】:2021-09-08 09:42:49
【问题描述】:

我想在标头中有 const std::map 作为全局常量,将在其他 cpp-s 中使用。所以我将其声明为:

// header.h
const inline std::map<int, int> GlobalMap = { {1, 2}, {3, 4} };

但是,如果我在多个 cpp-s 中包含此标头,则会在退出时发生堆损坏,因为多个析构函数针对同一个内存地址运行。

我一直认为 inline const 是全局非文字常量的灵丹妙药。我已经将全局 std::string-s 声明为 const inline 并且它工作得很好。

所以我的问题是:

  1. 为什么会这样?这不是让const inline 很容易出错吗?
  2. 如何在 C++17 中正确声明全局 const std::map?以及如何确保只创建一个全局对象?

编辑: 我可以在 Visual Studio 2017 的以下项目中重现它(/std:c++17,Debug x86)

file_1.h:

#pragma once
#include <map>

const inline std::map<int, double> GlobalMap = {{1, 1.5}, {2, 2.5}, {3, 3.5}};

void f1();

file_1.cpp:

#include "file_1.h"

void f1()
{
    (void)GlobalMap;
}

main.cpp:

#include "file_1.h"

int main()
{
    f1();
    return 0;
}

【问题讨论】:

  • 这里只是猜测,但也许你忘了在顶部添加#pragma once
  • @Gal 不,#pragma 曾经在顶部
  • @Gal 为什么会有不同?
  • 您的解决方案应该没问题。问题出在其他地方。请提供一个复制案例。例如。您实际上可以在 wandbox 中创建多个文件:wandbox.org/permlink/rIFr1GkkKiJ1Ggzh
  • 对我来说看起来像一个 Visual C++ 错误。它在最新的 2019 年运行良好,而 VS 2017 的 C++17 支持可能确实存在一些小故障。

标签: c++ constants c++17 inline stdmap


【解决方案1】:

这看起来像一个 Visual Studio 错误:https://developercommunity.visualstudio.com/t/static-inline-variable-gets-destroyed-multiple-tim/297876

在发布时,该错误的状态为“已关闭 - 优先级较低”,即未修复。

来自the comment of the Microsoft representative

如果您在我们的最新版本中仍然遇到此问题,请将其报告为新问题。

所以我建议用 repro-case 提交一个新问题。

【讨论】:

  • 会的。顺便说一句,与报告中所写的相反,这个错误体现在我们应用程序的发布版本中。不过,我无法为此创建一个小型复制案例。
  • 关于 Release 的注释非常重要,我相信它会影响 MS 人员优先考虑问题的方式。
  • 更新:我的错误报告已关闭为重复,该问题已报告并已在 VS 2019 16.0 中修复。见developercommunity.visualstudio.com/t/…
【解决方案2】:

关于 C++17 中的第二个问题,您可以应用此修复,以便在整个项目中只有一个地图实例

struct Globals
{
    static inline const std::map<int, int> Map = { {1, 2}, {3, 4} };
};

或者你可以使用extern:

  1. my_global.h

    #ifndef my_global_h
    #define my_global_h
    
    #include <map>
    
    extern const std::map<int, int> GlobalMap;
    
    #endif /* my_global_h */
    
  2. my_global.cpp

    #include "my_global.h"
    const std::map<int, int> GlobalMap = { {1, 2}, {3, 4} };
    

但在我看来,第一个解决方案要好得多。

P.S.我已将您的代码行放入一个头文件中,将该头文件包含在多个 *.cpp 中后,我的程序编译并退出时没有错误,GlobalMap 的地址是在所有翻译单元中都相同。 所以我同意@Mikhail 的观点,如果你能向我们提供一些复制案例,那就太好了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多