在 Visual Studio 中使用 C++17 静态内联成员时的奇怪行为

Strange behaviour when using C++17 static inline members in Visual Studio

昨天问了这个问题,没能给出MVCE。我设法用一个简单的程序重现了这一点。问题在于使用 std::list 作为 class 中的静态内联声明。 Microsoft Visual Studio 确实支持这个新的 C++17 特性。截至 3 月,它有一些错误,但据我所知,它们已被修复。以下是如何解决此问题的说明,这发生在调试模式下。

main.cpp

#include <iostream>
#include "header1.h"

int main()
{
    return 0;
}

header1.h中:

#include <list>

struct Boo
{
    static inline std::list<int> mylist;
};

anotherCPP.cpp

#include "Header1.h"

当程序退出 main() 时,它会销毁所有静态 objects 并抛出异常。

如果这没有崩溃,也许在你的系统上 compiler/linker 优化了一些代码,所以你可以尝试制作 main.cppanotherCPP.cpp 做某事。在 anotherCPP.cpp:

#include <iostream>
#include "Header1.h"

void aFunction()
{
    std::cout << Boo::mylist.size();
}

并使 main.cpp:

#include <iostream>
#include "Header1.h"

void aFunction();

int main()
{
    std::cout << Boo::mylist.size();
    afunction();

    return 0;
}

当程序退出时,当 std::list 被清除时,我在这里得到一个异常。这是崩溃的 Visual Studio 调试代码:

for (_Nodeptr _Pnext; _Pnode != this->_Myhead(); _Pnode = _Pnext)
{   // delete an element
    _Pnext = _Pnode->_Next; // Here: Exception thrown: 
                            // read access violation.
                            // _Pnode was 0xFFFFFFFFFFFFFFFF.

    this->_Freenode(_Pnode);
}

仅当我在 class 中声明静态内联 std::list mylist 时才会发生这种情况。如果我在我的 class 中将其声明为 static std::list< int > mylist ,然后在一个 .cpp 中将其单独定义为 std::list< int > Boo::mylist; 它工作正常。当我声明 std::list 静态内联并且在两个 .cpp 文件中包含 class 的 header 时会出现此问题。

在我的项目中,我从上面逐步完成了 std::list 清除循环,我记下了 "this" 指针地址。我逐步执行了循环,因为它释放了我列表中的节点。然后它返回释放其他 std::lists,包括 std::unordered_map(因为从外观上看他们也使用 std::lists)。最后当读访问异常抛出,_Pnode为无效指针地址时,我注意到"this"指针地址与清除时的"this"指针地址相同std::list mylist,这让我觉得它试图删除它两次,这可能是它崩溃的原因。

我希望有人能重现这个,我不确定这是什么,如果它是一个错误或者我做错了什么。这也发生在我的 32 位和 64 位,但只在调试模式下,因为我提供的节点释放循环在宏下:

#if _ITERATOR_DEBUG_LEVEL == 2

此问题已作为错误 here 归档,标题为 "Multiple initializations of inline static data member in Debug mode"。

这是在 Visual Studio 2017 版本 15.7 中找到的。

VS 编译器团队已接受此问题并已在即将发布的版本中修复该问题。