Почему ~ не следует:: parse
Во время Андрея Александреску поговорим об обработке ошибок:
Смотрите С++ и Beyond 2012: Андрей Александреску - систематическая обработка ошибок на С++ (около 30 минут)
Андрей представляет следующий фрагмент кода:
~Expected()
{
using std::exception_ptr;
if (gotHam) ham.~T();
else spam.~exception_ptr();
}
Этот деструктор очищает a union
, который содержит либо некоторый тип T
, либо std::exception_ptr
. Объединение заполняется с помощью placement new
.
Затем Андрей объясняет, что using std::exception_ptr;
необходимо, потому что следующий код не анализирует:
else spam.~std::exception_ptr();
Это означает, что всегда необходимо иметь директиву using, если вам нужно явно вызвать деструктор класса в другом пространстве имен.
Почему второй пример не анализируется?
Может ли код followng быть допустимой альтернативой?
else delete spam;
Имеет ли это тот же эффект, что и явный вызов деструктора std::exception_ptr
Ответы
Ответ 1
Андрей, вероятно, использует using std::exception_ptr;
, потому что его компилятор сломан.
Нет необходимости. spam.~exception_ptr();
должен легко компилироваться без него.
3.4.5/3. Если unqualified-id - это имя типа, имя типа просматривается в контексте всего постфиксного выражения. Если тип T выражения объекта имеет тип класса C, имя типа также просматривается в области класса C.
Он действительно компилируется с помощью gcc.
Если по какой-то причине вам нужно использовать квалифицированное имя, spam.std::exception_ptr::~exception_ptr();
также компилируется.
Ответ 2
Проблема в том, что ~std::exception_ptr()
на самом деле не имя функции, которую вы пытаетесь вызвать, а просто ~exception_ptr()
. И поскольку он относится к классу в другом пространстве имен, он недоступен (EDIT: хотя он должен быть доступен в соответствии с § 3.4.5/3 в стандарте С++ 11, как указывает в его ответе, но Microsoft компилятор ведет себя таким образом).
У вас есть альтернатива приведению класса в ваше пространство имен: выполните явный вызов, используя имя квалифицированного класса:
else spam.std::exception_ptr::~exception_ptr(); // This is legal
Что касается вашего второго вопроса, как правильно объяснил Р. Мартиньо Фернандес в комментарии, вызов оператора delete
не эквивалентен просто вызову деструктора: он также вызывает неловко названную функцию operator delete()
.
Ответ 3
Синтаксис spam.~std::exception_ptr
не допускается, потому что грамматика запрашивает id-выражение и ~std::exception_ptr
не является одной, как указал Горпик, вам нужно spam.std::exception_ptr::~exception_ptr()
. Но я не понимаю причину, по которой требуется квалификация, в предложении, описывающем синтаксис, напомняется, что
поскольку имя класса вставляется в область его класса (раздел 9), имя класса также считается вложенным членом этого класса.
поэтому я думаю, что spam.~exception_ptr()
должен быть действительным даже без предложения use. BTW
namespace ns {
struct Foo {};
}
void f()
{
ns::Foo x;
x.~Foo();
}
скомпилировать со всеми g++, к которым я имею доступ (включая очень старый 2.95). Это, похоже, подтверждает мое мнение о том, что если он не работает в контексте обновленных типов объединения С++ 11, это ошибка в реализации.
Изменить, с g++ 4.7.1, следующий компилятор также с -std = С++ 11.
namespace ns {
struct Foo {};
}
struct Bar {};
union U {
ns::Foo f;
Bar b;
};
struct C {
bool b;
U u;
~C() {
if (b)
u.f.~Foo();
else
u.b.~Bar();
}
};
void f()
{
C c;
}
поэтому Андрей был отслежен (либо с ошибкой в компиляторе, который он использовал, либо забыв о том, что имена классов импортируются в область действия класса), пытающихся решить проблему, которая не нуждается в разрешении.