Я заметил небольшую неточность в том, как MSVC и g ++ обрабатывают создание объекта временного исключения, когда брошенный тип является подвижным.Охота на этих пухов подняла дополнительные вопросы.
Прежде чем идти дальше, вот в чем суть моего вопроса: в отсутствие права на копирование / перемещение, кто хорошо говорит в стандарте, как должен создаваться объект временного исключения?На данный момент лучшее, что я смог сделать, это следующая цитата из 15.1 / 3:
Выражение throw инициализирует временный объект, называемый объектом исключения, тип которогоопределяется путем удаления любых cv-квалификаторов верхнего уровня из статического типа операнда throw и настройки типа из «массива T» или «функции, возвращающей T», в «указатель на T» или «указатель на функцию, возвращающую T»соответственно.
Я предполагаю, что ответ похоронен где-то на другом языке, определяющем тип выражения и способ инициализации объектов, но мне не повезло объединить все вместе.Когда объект брошен, получает ли объект исключения (а) созданную копию, (б) перемещенную конструкцию, если это уместно, и копию, созданную иным образом, или (в) инициализированную способом, определяемым реализацией?код:
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
struct Blob {
Blob() { cout << "C" << endl; }
Blob(const Blob&) { cout << "c" << endl; }
Blob(Blob&&) { cout << "m" << endl; }
Blob& operator =(const Blob&) { cout << "=" << endl; return *this; }
Blob& operator =(Blob&&) { cout << "=m" << endl; return *this; }
~Blob() { cout << "~" << endl; }
int i;
};
int main() {
try {
cout << "Throw directly: " << endl;
throw Blob();
} catch(const Blob& e) { cout << "caught: " << &e << endl; }
try {
cout << "Throw with object about to die anyhow" << endl;
Blob b;
throw b;
} catch(const Blob& e) { cout << "caught: " << &e << endl; }
{
cout << "Throw with object not about to die anyhow (enter non-zero integer)" << endl;
Blob b;
int tmp;
cin >> tmp; //Just trying to keep optimizers from removing dead code
try {
if(tmp) throw b;
cout << "Test is worthless if you enter '0' silly" << endl;
} catch(const Blob& e) { cout << "caught: " << &e << endl; }
b.i = tmp;
cout << b.i << endl;
}
}
Это все воссоздано на ideone .Как вы можете (надеюсь) увидеть, gcc via ideone создает объект Blob
на месте в первом случае и перемещается во втором.Результаты приведены ниже, значения указателей заменены идентификаторами.
Throw directly:
C {A}
caught: {A}
~ {A}
Throw with object about to die anyhow
C {A}
m {B} <- {A}
~ {A}
caught: {B}
~ {B}
Throw with object not about to die anyhow (enter non-zero integer)
C {A}
m {B} <- {A}
caught: {B}
~ {B}
2
~ {A}
Один и тот же код в MSVC2010, независимо от настроек оптимизации, результаты одинаковы за исключением того, что два хода являются копиями.Это та разница, которая первоначально привлекла мое внимание.
Первый тест, который я предполагаю, в порядке;его классическая копия elision.
Во втором тесте gcc ведет себя так, как я ожидал.Временное значение Blob
обрабатывается как значение x, а объект исключения - это перемещение, созданное из него.Но я не уверен, требуется ли компилятору распознавать, что срок действия оригинального Blob
истекает;если это не так, то MSVC работает правильно, когда копирует.Таким образом, мой первоначальный вопрос: соответствует ли стандартный мандат тому, что здесь происходит, или это просто часть определенного реализацией поведения, не зависящего от обработки исключений?
Третий тест с точностью до наоборот: MSVC ведет себя так, как требует моя интуиция.gcc решает перейти с b
, но b
все еще жив, о чем свидетельствует тот факт, что я продолжаю работать с ним после обработки сгенерированного исключения.Очевидно, что в этом тривиальном примере перемещение или копирование не имеет никакого значения для самого b
, но, безусловно, компилятору не разрешается смотреть на это при рассмотрении разрешения перегрузки.
Очевидно, наличие копирования / перемещенияelision делает этот простой тест трудным для обобщения, но большая проблема заключается в том, что любой из компиляторов может быть еще не совместимым (особенно в случае gcc с третьим тестом и MSVC в целом).
Обратите внимание, что это исключительно для академических целей;Я почти никогда не выкидываю ничего, кроме временного, которое оба компилятора строят так или иначе, и я совершенно уверен, что поведение разрешено.