内联变量被初始化多次

问题描述 投票:0回答:3

我看到一些

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(您可以投票以帮助推动错误修复)

c++ visual-studio-2017 c++17 compiler-bug inline-variable
3个回答
7
投票

这似乎是 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

4
投票

我使用 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 开关也是如此。


3
投票

截至今天,Visual Studio 2017 已更新至版本 15.9.24,修复了该问题。

来自发行说明:

修复了 C++ 编译器错误,以正确折叠内联变量动态 初始化器。

© www.soinside.com 2019 - 2024. All rights reserved.