【问题标题】:(Known) compiler bug in VC12?(已知)VC12 中的编译器错误?
【发布时间】:2014-01-29 10:28:17
【问题描述】:

该程序在使用 VC12(在 Visual Studio 2013 RTM 中)[1] 编译时会导致崩溃(在所有构建配置中),而实际上它不应该:

#include <string>

void foo(std::string const& oops = {})
{
}

int main()
{
    foo();
}

我知道两个可能相关的无声的错误代码生成错误:

老实说,我认为这些是不同的。有谁知道

  1. 在连接上是否存在主动跟踪的错误
  2. 是否有解决方法(或明确描述导致此错误的情况,以便我们可以在代码库中查找/避免它)?

[1] 只需使用 C++ 控制台应用程序“向导”创建一个空项目。为简单起见,禁用预编译头并保留所有默认值:http://i.stack.imgur.com/rrrnV.png

【问题讨论】:

  • return 0; 丢失但似乎不相关...
  • @Mario,不需要。也不相关。
  • @Sehe connect.microsoft.com/VisualStudio/feedback/details/809243/… 怎么样?我不知道它是否相关或相关。
  • @remyabel 谢谢!这正是我一直在寻找的。如果您介意发布作为答案(如果您愿意,我可以添加一些解决方法),我们可以将其作为答案。
  • 看起来这是一般情况下的问题vc++ Vs clang and gcc

标签: c++ visual-c++ visual-studio-2013 compiler-bug


【解决方案1】:

看起来Visual Studio 在默认参数是初始化程序列表 时,它调用的构造函数只是被破坏了。这段代码:

#include <iostream>

struct test {
  test ()  { std::cout << "test ()" << std::endl ; } 
  test (int)  { std::cout << "test (int)" << std::endl ; }
};

void func( test const &s = {} )
{
}

int main()
{
    test s = {} ;
    func() ;
}

gccclang 中产生此结果,请参阅live here

test ()
test ()

Visual Studio 产生这个结果:

test ()
test (int)

对于这段代码:

#include <iostream>
#include <initializer_list>

struct test {
  test ()  { std::cout << "test ()" << std::endl ; };

  test (int)  { std::cout << "test (int)" << std::endl ; };
  test ( std::initializer_list<int>) { std::cout << "test (initializer_list<int>)" << std::endl ; } ;
};

void func( test const &s = {0} )
{
}

int main()
{
    test s = {0} ;
    func() ;
}

gccclang 产生这个结果看它live here:

 test (initializer_list<int>)
 test (initializer_list<int>)

Visual Studio 产生此错误:

 error C2440: 'default argument' : cannot convert from 'initializer-list' to 'const test &'
    Reason: cannot convert from 'initializer-list' to 'const test'
    No constructor could take the source type, or constructor overload resolution was ambiguous

更新

为了进行完整性检查,我回到了标准,以确保在这种差异的根源上没有一些奇怪的规则,或者可能是某些限制导致此代码格式错误。据我所知,这段代码不是格式错误的8.3.5 语法部分特别允许这样做:

parameter-declaration:
  attribute-specifier-seqopt decl-specifier-seq declarator
  attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
  [...]

这似乎不像 8.5 部分 Initializers8.3.6 默认参数 添加任何限制,但此缺陷报告 994. braced-init-list as a default argument 和工作文件 Wording for brace-initializers as default arguments 使很明显,它是有意的,并概述了对标准所做的更改以允许它,并且查看增量没有明显的限制。

【讨论】:

【解决方案2】:

November 中发布了一个活跃的问题。发布的示例代码是:

Compile and run following code in VS2013

#include <string>

void f(std::string s = {}) {
}

int main(int argc, char* argv[]) {
    f();
    return 0;
}

微软已确认该错误。

那里似乎没有发布解决方法。 编辑 解决方法可以很容易地基于避免使用列表初始化器语法:

void f(std::string s = "");
void f(std::string s = std::string());
void f(std::string s = std::string {});

或者只是老式的(如果您不介意引入重载):

void f(std::string s);
void f() { f(std::string()); }

【讨论】:

  • 我添加了明显的解决方法。这在一定程度上回答了要寻找什么的问题。我猜想寻找={}{{},{} 在某种程度上可以找到这种情况。不过,我不能完全放心,这会找到(所有)相关的呼叫站点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-15
  • 2021-06-09
相关资源
最近更新 更多