C ++右值引用行为(具体示例)

时间:2015-04-02 10:13:27

标签: c++ c++11 rvalue-reference

我目前正在尝试使用libc ++来编译和运行MSVC。在这样做的过程中,我遇到了一个令人讨厌的错误(至少我认为是一个错误),这已经花了我一段时间来确定。我有以下repro代码:

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中不起作用。在 foo 中,变量 rval 指向堆栈上的临时值,因此全局变量永远不会增加。

临时是在int&amp;&amp ;; operator *()const。如果我更换:

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

return std::move(*i);
然后一切都很顺利。使用C-cast也会导致临时创建。

2 个答案:

答案 0 :(得分:8)

  

1)这是否合法,即我是否避免陷入其中   未定义的行为(它在语法上是合法的)?

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

  

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

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

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

答案 1 :(得分: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在从一个切换到另一个时给出不同的结果,那显然是一个错误。