(已知)VC12中的编译器错误?

seh*_*ehe 26 c++ visual-c++ compiler-bug visual-studio-2013

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

#include <string>

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

int main()
{
    foo();
}
Run Code Online (Sandbox Code Playgroud)

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

老实说,我认为这些是不同的.有人知道吗

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

[1]使用C++ Console Application'向导'创建一个空项目.为简单起见,请禁用预编译标头并保留所有默认值:http://i.stack.imgur.com/rrrnV.png

Sha*_*our 11

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() ;
}
Run Code Online (Sandbox Code Playgroud)

产生这个结果,gccclang看到它住在这里:

test ()
test ()
Run Code Online (Sandbox Code Playgroud)

Visual Studio产生这个结果:

test ()
test (int)
Run Code Online (Sandbox Code Playgroud)

并为此代码:

#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() ;
}
Run Code Online (Sandbox Code Playgroud)

gccclang产生这个结果看到它住在这里:

 test (initializer_list<int>)
 test (initializer_list<int>)
Run Code Online (Sandbox Code Playgroud)

同时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
Run Code Online (Sandbox Code Playgroud)

更新

对于一个全面的检查,我又回到了标准,以确保有没有在这种差异或许有一定的约束,使这个代码的根源一些奇怪的规则形成不良.据我所知,这段代码不是格式错误.Section 8.3.5语法特别允许这样:

parameter-declaration:
  attribute-specifier-seqopt decl-specifier-seq declarator
  attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
  [...]
Run Code Online (Sandbox Code Playgroud)

看起来似乎没有部分8.5 初始化器8.3.6 默认参数添加任何限制,但是这个缺陷报告994.braced-init-list作为默认参数和工作文件作为默认参数的大括号初始化器的措辞明确表明它是有意的并概述了更改制定标准允许它并且看三角洲没有明显的限制.


小智 8

11月发布了一个活跃的问题.发布的示例代码是:

Compile and run following code in VS2013

#include <string>

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

int main(int argc, char* argv[]) {
    f();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

该漏洞已得到微软的认可.

似乎没有在那里发布的解决方法.编辑变通办法很容易基于避免list-initializer语法:

void f(std::string s = "");
void f(std::string s = std::string());
void f(std::string s = std::string {});
Run Code Online (Sandbox Code Playgroud)

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

void f(std::string s);
void f() { f(std::string()); }
Run Code Online (Sandbox Code Playgroud)