我看到一些
inline const
变量在 Visual Studio 2017 中初始化(和销毁)3 次的示例。这是链接器的错误吗?或者这应该以其他方式发生?
链接器 Comdat 折叠设置为关闭。
示例代码:
#pragma once
struct A {
A() {
static int count = 0;
++count;
ASSERT(count == 1);
}
~A() {
}
};
inline const A a = A();
在我的解决方案中,我让断言触发两次(构造函数调用了 3 次)。 检查调用堆栈显示所有调用堆栈都是相同的,并且所有调用都来自 a() 的动态初始化程序。现在我知道这个类没有在解决方案的其他部分中使用,因为我只是创建它来调查这个问题。
我使用的是 VS17 15.8.9
更新:此处报告错误https://developercommunity.visualstudio.com/content/problem/297876/static-inline-variable-gets-destroyed-multiple-tim.html(您可以投票以帮助推动错误修复)
这似乎是 MSVC 的错误。我可以使用下面的代码重现它(也可以使用 VS2017 15.8.9)。有趣的是,我只能使用调试版本进行重现。在发布模式下,优化器似乎拯救了我们。
Common.h
#pragma once
#include <iostream>
class Foo
{
public:
Foo()
{
std::cout << "Constructing a Foo" << std::endl;
}
~Foo()
{
std::cout << "Destructing a Foo" << std::endl;
}
};
inline Foo const Bar;
其他.cpp
#include "common.h"
void DoOtherStuff()
{
std::cout << &Bar << std::endl;
}
main.cpp
#include "common.h"
void DoStuff()
{
std::cout << &Bar << std::endl;
}
extern void DoOtherStuff();
int main()
{
DoStuff();
DoOtherStuff();
}
输出(调试)
Constructing a Foo
Constructing a Foo
00007FF74FD50170
00007FF74FD50170
Destructing a Foo
Destructing a Foo
我使用 MS C++ 编译器版本 19.16(例如,Visual Studio 15.9.4 附带)在调试和发布 (/Ox) 模式下都遇到了该错误。
内联.Hpp
#include <iostream>
inline struct Foo
{ Foo() { std::cout << "Constructing a Foo at " << this << std::endl; } }
Instance;
内联.cpp
#include "Inline.Hpp"
int main() { return 0; }
Inline2.cpp
#include "Inline.Hpp"
编译链接inline.cpp和inline2.cpp后,运行输出为:
Constructing a Foo at 00BE4028
Constructing a Foo at 00BE4028
编译器和链接器正确地将两个内联定义解析为单个对象,但错误地为每个定义调用构造函数,而不是只调用一次。这是一个严重的错误,导致 C++17 的“内联变量”功能无法使用。 “解决方法”是将内联变量视为自版本 19.16 起仍不受 MS C++ 支持,即使使用 /std:c++17 开关也是如此。