我希望以下程序一直返回0。但是,对于Visual Studio 2013(Update 4),程序在发布版本中退出1。我不确定这是一个错误,还是编译器的优化器是正确的,并且依赖于某些边缘行为。如果CONST宏被关闭,那么release exe返回0.如果优化器确实是正确的,我是否可以获得允许它发出代码的原因?
#if 1
# define CONST const
#else
# define CONST
#endif
class TypeId {
public:
bool operator== (TypeId const & other) const
{
return id == other.id;
}
private:
TypeId (void const * id)
: id(id)
{}
public:
template <typename T>
static TypeId Get ()
{
static char CONST uniqueMemLoc = 0;
return TypeId(&uniqueMemLoc);
}
private:
void const * id;
};
int main(int, char **)
{
typedef int A;
typedef unsigned int B;
if (TypeId::Get<A>() == TypeId::Get<B>()) {
return 1;
}
return 0;
}
答案 0 :(得分:15)
这似乎不是根据草案C ++ 11标准部分14.8
[temp.fct.spec] 所说的有效优化(强调我的前进< / em>的):
从模板实例化的每个功能模板专业化 它自己的任何静态变量的副本。 [例如:
template<class T> void f(T* p) { static T s; }; void g(int a, char* b) { f(&a); // calls f<int>(int*) f(&b); // calls f<char*>(char**) }
这里f(int *)有一个类型为int和的静态变量s f(char **)有一个char *类型的静态变量。 - 例子]
由于您使用变量的地址折叠它们会影响可观察的行为,这会违反as-if rule。
T.C。指出/opt:noicf
可以防止不合规行为。
Matt McNabb指出/OPT (Optimizations) documentation包含以下注释:
因为/ OPT:ICF可以导致分配相同的地址 不同的函数或只读数据成员(const变量 通过使用/ Gy)编译,它可以打破依赖于唯一的程序 功能或只读数据成员的地址。更多 信息,请参阅/ Gy(启用功能级链接)。
这表明这可能是故意的不合规行为。 Ben Voigt says in a comment now moved to chat这确实意味着优化可以不符合,但这一点值得商榷。
将用户linked发送至MS blog post: Introducing ‘/Gw’ Compiler Switch并说明:
请注意, ICF优化仅适用于相同的情况 没有接收地址的COMDAT ,它们是只读的。如果一个 数据不是地址,然后由ICF打破地址唯一性 不会导致任何可观察到的差异,因此它是有效的 符合标准。
以后的评论说:
即使它完全是标准投诉,但是 结合/ Gy可能导致破坏行为。
从我所知道的为/Gy
影响 const 变量 __ declspec(selectany)必须使用但在文档中可能更清楚
至少我们可以看到/Gw
不应该引入不合规行为,/Gy
可能与/Gw
结合使用。
答案 1 :(得分:7)
不,这种优化不符合C ++标准。 uniqueMemLoc
的声明为模板的每个实例定义了一个唯一的对象,每个对象都有自己的地址。
(如果您使用了字符串文字,那将是一个不同的故事。在这种情况下,优化将是有效的。)