Почему ~ не следует:: parse - программирование

Почему ~ не следует:: 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

4b9b3361

Ответ 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;
}

поэтому Андрей был отслежен (либо с ошибкой в ​​компиляторе, который он использовал, либо забыв о том, что имена классов импортируются в область действия класса), пытающихся решить проблему, которая не нуждается в разрешении.