2015-04-02 3 views
2

В настоящее время я пытаюсь получить libC++ для компиляции и запуска с помощью MSVC. При этом я столкнулся с неприятной ошибкой (по крайней мере, я думаю, это ошибка), которая заставила меня подождать. У меня есть следующий код: REPROC++ rvalue reference behavior (конкретный пример)

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) Что такое ожидаемое значение глобальной переменной globalInt после возврата foo (неопределенный может быть приемлемым ответом)?

EDIT:

мне дали понять, что это не работает в VS с MSVC 12. В обув переменная RVAL наведен на временное на стек и, таким образом, глобальный переменная никогда не увеличивается.

Временное создаётся в int & & оператор *() const. Если я заменяю:

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

с

return std::move(*i); 

то все хорошо. Использование C-cast также создает временное создание.

+0

Позвольте мне угадать, MSVC создает временную с этим 'static_cast'? Это не должно. –

+0

Пятно на! Известная проблема? –

+0

Я просто догадывался, как вы сформулировали свой вопрос. Но я не удивлюсь, если это известная ошибка. –

ответ

8

1) Является ли это законным, т.е. я избегал отклоняясь в сферах неопределенного поведения (это, конечно, синтаксически юридическое)?

Вы так, так близко. __i является зарезервированным идентификатором, и преобразование 0xff в char, скорее всего, будет определяться реализацией. Кроме этого, этот код действителен и поведение корректно определено.

2) Что такое ожидаемое значение глобальной переменной globalInt после Foo возвращается (не определено, может быть приемлемым ответом)?

667. Ссылка, возвращаемая static_cast<int&&>(*__i), связывается непосредственно с *__i - то есть, globalInt. Временного не должно быть создано. Соответствующее правило в [expr.static.cast]/p3 остается практически неизменным с C++ 11, поэтому вы определенно видите ошибку компилятора здесь.

Похоже, что эта ошибка была исправлена ​​в следующей версии VC++, основанной на тестировании на http://webcompiler.cloudapp.net/.

+0

Ха, приятно на комментарий __i. Этот код был взят из libcxx, где его использование действительно. Спасибо за ссылку на компилятор облака. Никогда не видел этого раньше. И да, действительно, похоже, что там работает. Никакой помощи для меня, поскольку мне это нужно, чтобы работать в более ранних версиях. –

+0

Можете ли вы сказать мне, почему globalInt должен быть 667, а не в неопределенном состоянии? – Logman

+0

Интересный qn Logman. Я предполагаю, что вы спрашиваете, каковы гарантии на C++ lvalue после преобразования его в ссылку rvalue? Из реализации я «знаю», что она будет в определенном состоянии (ошибки в модуле компилятора!), Но со стандартной точки зрения я не уверен, что вы можете сделать. Становится ли оно значением x и, следовательно, в неопределенном состоянии? Я должен был бы оставить это кому-то, лучше разбирающемуся со стандартами, чем я, к сожалению! –

1

В ++ Язык программирования C (4-е издание), Страуструп состояния (§7.7.2, стр 195).:

[...] стандартная библиотека предоставляет функцию move(): move(x) означает static_cast<X&&>(x), где X - тип x.

Более точно, от стандарта 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 является ИНТ, std::move() и static_cast<int&&>() точно то же самое.

Итак, если MSVC дает разные результаты при переключении с одного на другой, это явно ошибка.

+0

Определение 'std :: move' немного сложнее, чем это; BS перефразирует. –

+0

@MattMcNabb Я обновил свой ответ, вставленный со стандарта. –