Что стандарт C ++ говорит о потере спецификатора throw в деструкторе по умолчанию - PullRequest
19 голосов
/ 09 марта 2012

Три различных компилятора показывают три различных поведения, компилирующих этот код:

class MyException : public std::exception
{
 public:
  MyException(std::string str) : m_str(str) {}
  virtual const char * what() const throw () {return m_str.c_str(); }
 protected:
  std::string m_str;
};

Sun C ++ 5.8 Patch 121017-22 2010/09/29: Предупреждение Функция MyException :: ~ MyException () может выдавать только исключения, выданные функцией std :: exception :: ~ exception (), которую он переопределяет

g ++ 3.4.3: Ошибка более слабый спецификатор броска для `virtual MyException :: ~MyException () '

Visual Studio 2005: Очень рад (ни об ошибке, ни предупреждении)

class exception {
public:
  exception () throw();
  exception (const exception&) throw();
  exception& operator= (const exception&) throw();
  virtual ~exception() throw();
  virtual const char* what() const throw();
}

Я знаю, в чем проблема и как я могу ее исправитьit:

class MyException : public std::exception
{
 public:
  MyException(std::string str) : m_str(str) {}
  virtual const char * what() const throw () {return m_str.c_str(); }
  ~MyException() throw() {}  <------------ now it is fine!
 protected:
  std::string m_str;
};

Однако мне интересно, что говорит стандарт в конкретной ситуации.

Я провел еще один небольшой тест в Visual Studio 2005 и обнаружил кое-что, чтоменя действительно удивляет:

struct Base
{
    virtual int foo() const throw() { return 5; }
};

struct Derived : public Base
{
    int foo() const { return 6; }
};

int main()
{
    Base* b = new Derived;
    std::cout << b->foo() << std::endl; //<-- this line print 6!!!
    delete b;
}

Подпись двух функций различна.Как это может работать?Кажется, что Visual Studio 2005 полностью игнорирует спецификацию исключений.

struct Base
{
    virtual int foo() const throw() { return 5; }
};

struct Derived : public Base
{
    int foo() { return 6; } // I have removed the const keyword 
                            // and the signature has changed
};

int main()
{
    Base* b = new Derived;
    std::cout << b->foo() << std::endl; // <-- this line print 5
    delete b;
}

Это стандарт c ++?Можно ли установить какой-либо магический флаг?

А как насчет VS2008 и VS2010?

Ответы [ 2 ]

6 голосов
/ 09 марта 2012

Ваша программа некорректна в соответствии со стандартом C ++ и поэтому демонстрирует поведение, которое не может быть объяснено в рамках стандарта C ++.

Справка:
Стандарт C ++ 03:

15.4 Исключительные характеристики [исключением.spec]

Если виртуальная функция имеет спецификацию исключений, все объявления, включая определение любой функции, которая переопределяет эту виртуальную функцию в любом производном классе, должны разрешать только те исключения, которые разрешены спецификацией исключений базового класса виртуальная функция.

[Пример:

 struct B 
 {
    virtual void f() throw (int, double);
    virtual void g();
 };
 struct D: B 
 {
    void f(); // ill-formed
    void g() throw (int); // OK
 };

Объявление D::f является некорректным, поскольку допускает все исключения, тогда как B::f допускает только int и double. ]

5 голосов
/ 09 марта 2012

Это немного изменилось в C ++ 11 [исключением. Spec] :

5 / Если виртуальная функция имеет спецификацию исключенийвсе объявления, включая определение любой функции, которая переопределяет эту виртуальную функцию в любом производном классе, должны разрешать только те исключения, которые разрешены спецификацией исключений для виртуальной функции базового класса.

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

Однако этот случай сложен, поскольку деструктор фактически синтезируется самим компилятором!

В C ++ 03Я думаю, что Стандарт не был так осторожен с ними, и вы должны были написать их сами, в C ++ 11, однако мы получаем:

14 / Неявно объявленный специальныйФункция-член (раздел 12) должна иметь спецификацию исключений.Если f является неявно объявленным конструктором по умолчанию, конструктором копирования, конструктором перемещения, деструктором, оператором копирования или операцией назначения перемещения, его неявная спецификация исключения определяет идентификатор типа T тогда и только тогда, когда разрешено Tспецификацией исключений для функции, непосредственно вызываемой неявным определением f;f разрешает все исключения, если любая функция, которую он непосредственно вызывает, разрешает все исключения, а f не допускает никаких исключений, если каждая функция, которую он непосредственно вызывает, не допускает исключений.

Где компилятор будет генерироватьспецификация исключения деструктора, чтобы он соответствовал тому, что может быть выброшено из вызываемых им функций (т. е. деструкторов атрибутов).Если эти деструкторы не сгенерируют, он сгенерирует деструктор noexcept, который будет удовлетворять ограничению базового класса.

Примечание: VS2005 - один из наименее совместимых со стандартом компиляторов, который вы можете найти на Земле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...