header 中的 const inline std::map 在退出时导致堆损坏

const inline std::map in header causes heap corruption at exit

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

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

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

我一直认为内联常量是全局 non-literal 常量的灵丹妙药。我已经将 global std::string-s 声明为 const 内联并且它工作得很好。

所以我的问题是:

  1. 为什么要这样做?它不会使 const 内联很容易出错吗?
  2. 如何在 C++17 中正确声明全局 const std::map?我如何确保只创建一个全局 object?

编辑: 我可以在 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;
}

关于你在 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 的观点,如果您向我们提供一些重现案例,那就太好了。

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

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

来自the comment of the Microsoft representative

If you still face this issue in our latest version, please report it as a new problem.

所以我建议用重现案例提交一个新问题。