简体   繁体   English

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

[英]C++ rvalue reference behaviour (specific example)

I'm currently trying to get libc++ to compile and run with MSVC. 我目前正在尝试使用libc ++来编译和运行MSVC。 In doing so I encountered a nasty bug (at least what I think is a bug) which has taken me a while to pin down. 在这样做的过程中,我遇到了一个令人讨厌的错误(至少我认为是一个错误),这已经花了我一段时间来确定。 I have the following repro code: 我有以下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;
}

I have a few questions: 我有几个问题:

1) Is this legal, ie have I avoided straying into the realms of undefined behaviour (it is certainly syntactically legal)? 1)这是合法的,即我是否避免陷入未定义行为的领域(它在语法上是合法的)?

2) What is the expected value of the global variable globalInt after foo returns (undefined may be an acceptable answer)? 2)foo返回后全局变量globalInt的期望值是多少(未定义可能是可接受的答案)?

EDIT: 编辑:

I should have made clear that this isn't working in VS with MSVC 12. In foo the variable rval is pointing to a temporary on the stack and thus the global variable is never incremented. 我应该已经明确表示这在VS与MSVC 12中不起作用。在foo中 ,变量rval指向堆栈上的临时变量,因此全局变量永远不会递增。

The temporary is created in int&& operator*() const. 临时是在int && operator *()const中创建的。 If I replace: 如果我更换:

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

with

return std::move(*i);

then all is well. 那一切都很好。 Using a C-cast also causes the temporary to be created. 使用C-cast也会导致临时创建。

1) Is this legal, ie have I avoided straying into the realms of undefined behaviour (it is certainly syntactically legal)? 1)这是合法的,即我是否避免陷入未定义行为的领域(它在语法上是合法的)?

You are so, so close. 你是如此,如此接近。 __i is a reserved identifier, and the conversion of 0xff to char is likely implementation-defined. __i是保留标识符, 0xffchar的转换可能是实现定义的。 Other than that, this code is valid and the behavior is well-defined. 除此之外,此代码有效且行为定义明确。

2) What is the expected value of the global variable globalInt after foo returns (undefined may be an acceptable answer)? 2)foo返回后全局变量globalInt的期望值是多少(未定义可能是可接受的答案)?

667 . 667 The reference returned by static_cast<int&&>(*__i) binds directly to *__i - ie, globalInt . static_cast<int&&>(*__i)返回的引用直接绑定到*__i - 即globalInt No temporary should be created. 不应该创建临时。 The applicable rule, in [expr.static.cast]/p3, has remained substantially the same since C++11, so you are definitely seeing a compiler bug here. [expr.static.cast] / p3中的适用规则自C ++ 11以来基本保持不变,因此您肯定会看到编译器错误。

It looks like this bug has been fixed in the next version of VC++, based on testing on http://webcompiler.cloudapp.net/ . 根据http://webcompiler.cloudapp.net/上的测试,在下一版本的VC ++中修复了这个bug。

In The C++ programming language (4th edition) , Stroustrup states (§7.7.2, pg. 195): C ++编程语言(第4版)中 ,Stroustrup声明(§7.7.2,第195页):

[...] the standard library provides a move() function: move(x) means static_cast<X&&>(x) where X is the type of x . [...]标准库提供了move()函数: move(x)表示static_cast<X&&>(x)其中Xx的类型。

More precisely, from the C++11 standard (iso.20.2.3): 更确切地说,从C ++ 11标准(iso.20.2.3):

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

If your type T is an int, std::move() and static_cast<int&&>() are exactly the same thing. 如果类型T是int,则std::move()static_cast<int&&>()完全相同。

So, if MSVC gives different results when switching from one to another, it's clearly a bug. 因此,如果MSVC在从一个切换到另一个时给出不同的结果,那显然是一个错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM