2015-04-02 66 views
2

我目前正试图让libC++编译并使用MSVC运行。在这样做的过程中,我遇到了一个令人讨厌的bug(至少我认为是一个bug),这让我花了一段时间才搞定。我有以下的摄制代码:C++右值引用行为(具体示例)

int globalInt = 666; 

class mini_move_iterator 
{ 
public: 

    mini_move_iterator(int* i) : __i(i){} 

    int&& operator*() const 
    { 
     return static_cast<int&&>(*__i); 
    } 

    int* __i; 
}; 

void foo(int&& rval) 
{ 
    // Smash stack 
    char stackUser[1000]; 
    for (int i = 0; i < 1000; ++i) 
     stackUser[i] = 0xff; 

    rval += 1; 
} 

int main() 
{ 
    mini_move_iterator mmi(&globalInt); 
    foo(*mmi); 
    return 0; 
} 

我有几个问题:

1)这一法律,即有我避免误入未定义行为的领域(这肯定是语法上合法的)?

2)foo返回后(未定义可能是一个可接受的答案),全局变量globalInt的期望值是多少?

编辑:

我应该明确表示,这不是在VS正与MSVC 12. 变量RVAL指向一个临时的堆栈,因此全球变量永远不会增加。

临时创建于int & & operator *()const。如果我更换:

return static_cast<int&&>(*__i); 

return std::move(*i); 

就万事大吉了。使用C-cast也会导致临时创建。

+0

让我猜测,MSVC正在创建一个临时的'static_cast'?它不应该。 – 2015-04-02 10:19:48

+0

现货!已知问题? – 2015-04-02 10:23:19

+0

我只是猜测你构思你的问题的方式。但如果这是一个已知的错误,我不会感到惊讶。 – 2015-04-02 10:26:20

回答

8

1)这是合法的,也就是说,我是否避免误入 未定义的行为(它在语法上肯定是合法的)?

你是如此,如此接近。 __i是一个保留的标识符,并且0xffchar的转换可能是实现定义的。除此之外,此代码是有效的,行为已定义良好。

2)什么是全局变量globalInt后 富回报的预期值(未定义可能是一个可以接受的答案)?

667。由static_cast<int&&>(*__i)返回的参考直接结合到*__i--即globalInt。不应该创建临时的。 [expr.static.cast]/p3中的适用规则自C++ 11以来基本保持不变,因此您肯定会在这里看到一个编译器错误。

看起来这个bug已经在VC++的下一个版本中得到修复,基于http://webcompiler.cloudapp.net/的测试。

+0

哈,对__i评论很好。该代码从libcxx中分裂出来,在那里它的使用是有效的。感谢链接到云编译器。以前从未见过。确实,它似乎在那里工作。没有帮助,因为我需要它在早期版本中工作。 – 2015-04-02 10:35:46

+0

你能告诉我为什么globalInt应该是667而不是未定义的状态? – Logman 2015-04-02 12:08:03

+0

有趣的qn Logman。我认为你所要求的是将其转换为右值引用后,C++左值的保证是什么?从一个实现我“知道”它将处于一个确定的状态(模仿编译器错误!),但从标准的角度来看,我不知道你能推断出什么。它变成了一个xvalue,因此处于一个未定义的状态?不幸的是,我不得不把这件事留给比我更熟悉标准的人。 – 2015-04-03 07:18:00

1

的C++编程语言(第4版),Stroustrup的状态(§7.7.2,第195):

[...]标准库提供了一个move()函数:move(x)意味着static_cast<X&&>(x)其中Xx的类型。

更准确地,从C++ 11标准(iso.20.2.3):

template <class T> typename remove_reference<T>::type&& move(T&& t) noexcept; 返回static_cast<typename remove_reference<T>::type&&>(t)

如果你的类型T是一个int,std::move()static_cast<int&&>()是完全一样的东西。

因此,如果MSVC在从一个切换到另一个时给出不同的结果,这显然是一个错误。

+0

'std :: move'的定义比这更复杂一点; BS是释义。 – 2015-04-02 11:40:05

+0

@MattMcNabb我已经更新了从标准粘贴的答案。 – 2015-04-02 12:06:42