Error looser throw specifier for virtual

What does this error mean? How can I fix it? This is the header code that's causing it: class BadJumbleException : public exception { public: BadJumbleException (const string& msg); //

What does this error mean? How can I fix it? This is the header code that’s causing it:

class BadJumbleException : public exception {
public:
    BadJumbleException (const string& msg); // Constructor, accepts a string as the message
    string& what();                         // Returns the message string
private:
    string message;                         // Stores the exception message
};

And this is the source code:

BadJumbleException::BadJumbleException (const string& m) : message(m) {}
string& BadJumbleException::what() { return message; }

EDIT: This is the error:

looser throw specifier for ‘virtual BadJumbleException::~BadJumbleException()

Nathan Monteleone's user avatar

asked Mar 27, 2014 at 20:36

user2824889's user avatar

7

In C++03, per §18.6.1/5, std::exception has a destructor that is declared such that no exceptions can be thrown out of it (a compilation error will be caused instead).

The language requires that when you derive from such a type, your own destructor must have the same restriction:

virtual BadJumbleException::~BadJumbleException() throw() {}
//                                                ^^^^^^^

This is because an overriding function may not have a looser throw specification.


In C++11, std::exception::~exception is not marked throw() (or noexcept) explicitly in the library code, but all destructors are noexcept(true) by default.

Since that rule would include your destructor and allow your program to compile, this leads me to conclude that you are not really compiling as C++11.

answered Mar 27, 2014 at 20:51

Lightness Races in Orbit's user avatar

5

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

Уменьшение размера бинарного файла

Давайте рассмотрим следующий пример, в котором комментариями рассказывается, что за код генерируется компилятором:

#include <iostream>

class my_class {
    int i_;

public:
    explicit my_class (int i)
        : i_(i)
    {}

    int get() const {
        return i_;
    }
};

inline int operator+(const my_class& v1, const my_class& v2) {
    return v1.get() + v2.get();
}

int main() {
    int res = 0;
    try {
        // Если при вызове конструктора для var0 произойдет исключение,
        // распечатываем сообщение об ошибке и выставляем res в -1
        my_class var0(10);

        // Если при вызове конструктора для var1 произойдет исключение,
        // то компилятор должен будет вызвать деструктор
        // переменной var0, распечатать сообщение об ошибке
        // и выставить res в -1
        my_class var1(100);

        // Если при сложении произошло исключение,
        // распечатываем сообщение об ошибке и выставляем res в -1
       
        // Вызов деструкторов var1 и var0 произойдет в любом случае,
        // вне зависимости от генерации исключения.
        res = (var1 + var0 > 0 ? 0 : 1);
    } catch (...) {
        std::cerr << "Произошла ошибка";
        res = -1;
    }

    return res;
}

Многовато кода генерируется компилятором, не правда ли? Именно из-за такого разбухания кода, в некоторых крупных корпорациях (не будем тыкать пальцем в Google) при разработке на С++ запрещено использование исключений. Еще одним примером могут послужить правила разработки для GCC начиная с версии 4.8 (да, GCC теперь разрабатывается с использованием С++, см изменения для 4.8).

Давайте модифицируем класс my_class, чтобы он использовал noexcept и посмотрим что может генерировать компилятор:

class my_class {
    int i_;

public:
    explicit my_class (int i) noexcept
        : i_(i)
    {}

    int get() const noexcept {
        return i_;
    }
};

inline int operator+(const my_class& v1, const my_class& v2) noexcept {
    return v1.get() + v2.get();
}

int main() {
    // std::terminate при исключении
    my_class var0(10);

    // std::terminate при исключении
    my_class var1(100);
       
    // std::terminate при исключении
    int res = (var1 + var0 > 0 ? 0 : 1);

    // Вызов деструкторов var1 и var0
    return res;
}

Заметьте, что std::cerr больше не используется, а следовательно компилятор сможет убрать очень большой кусок кода. Но даже без этого, количество сгенерированного кода стало меньше.

К несчастью, мы рассматривали идеальный компилятор. На практике все может оказаться не так здорово: фича достаточно новая, не все компиляторы умеют хорошо ее использовать при оптимизациях.
Так же, некоторые компиляторы

иногда

и без noexcept могут определить, будут класс или метод кидать исключения.

Вот результаты компиляции различных версий одного класса на GCC 4.7.2:
1) Первоначальный класс, тело main из первого варианта, флаги -std=c++0x -fno-inline -O2: 5280 байт
2) Класс оптимизирований, тело main из второго варианта, флаги -std=c++0x -fno-inline -O2: 4800 байт

3) Класс оптимизирований, тело main из первого варианта, флаги -std=c++0x -fno-inline -O2: 5280 байт
4) Класс оптимизирований, тело main из первого варианта без iostream, флаги -std=c++0x -fno-inline -O2: 4800 байт
5) Класс оптимизирований, тело main из второго варианта + iostream включается, флаги -std=c++0x -fno-inline -O2: 5280 байт

* Флаг -std=c++0x включает возможности C++11, который необходим для использования noexcept.
** При повторении эксперимента, не забудьте убрать отладочную информацию из бинарного файла.

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

Немного схитрим, и разнесем метод main() и имплементацию my_class по разным файлам, чтобы компилятору было сложнее оптимизировать.
Результаты:
Первоначальный класс, тело main из первого варианта, флаги -std=c++0x -fno-inline -O2: 6952 байт
Класс оптимизирований, тело main из первого варианта, флаги -std=c++0x -fno-inline -O2: 5288 байт

Итого:

выигрыш в размере в 23.9% после добавления трех noexcept.

Ускорение работы стандартных алгоритмов

Для многих людей, использующих С++11 может стать большой неожиданностью данная часть стандарта N3050 (на данный момент этот стандарт реализован не во всех ведущих компиляторах). Если в кратце, в ней говорится, что стандартные алгоритмы и контейнеры не должны использовать move assignment и move construction если эти методы могут кидать исключения. Чем это может грозить рассмотрим на примере:

// Класс с ресурсоёмким копированием и быстрым move assignment
class move_fast_copy_slow {
    // Некие члены класса объявлены здесь
public:
    move_fast_copy_slow(move_fast_copy_slow&&);         // 1
    move_fast_copy_slow(const move_fast_copy_slow&);    // 2
   
    move_fast_copy_slow& operator=(move_fast_copy_slow&&);      // 3
    move_fast_copy_slow& operator=(const move_fast_copy_slow&); // 4
};

Если методы 1 и 3 не пометить noexcept, то стандартные контейнеры будут использовать более медленные методы 2 и 4. Вследствие этого работа с контейнерами std::vector и std::deque может замедлиться на пару порядоков. При том, данное замедление коснется и всех типов наследуемых или использующих move_fast_copy_slow в качестве члена.

Совместимость

На момент написания данной статьи не все ведущие компиляторы поддерживают noexcept. Используйте макрос BOOST_NOEXCEPT из библиотеки boost вместо noexcept для переносимости кода.

Подводные камни

По стандарту, noexcept не является частью типа функции, однако при использовании виртуальных функций все перегруженные функции должны иметь такую же либо более строгую спецификацию исключений. То есть следующий код не соберется:

class base {
public:
    virtual void foo() noexcept {}
};

class derived: public base {
public:
    void foo() override { throw 1; }
};

int main () {
    derived d;
    base *p = &d;
    p->foo();
}

Будет ошибка типа «error: looser throw specifier for ‘virtual void derived::foo()’».
Так что будьте готовы к тому, что если вы автор библиотеки и добавили спецификацию noexcept к фиртуальной функции, то у пользователей вашей библиотеки перестанет собираться код.
Так же приготовьтесь к тому, что ваши классы исключений c перегруженным методом what() и наследуемые от стандартных, могут не компилироваться если они не помечены noexcept:

class my_exception : public std::exception {
    const char* what() throw() { // В С++11 должно быть noexcept вместо throw()
        return "my_exception::what()";
    }
};

Заключение

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

Looser? Virtual? What?

looser throw specifier for 'virtual Error::~Error()'
... overriding 'virtual std::exception::~exception() throw ()'

While compiling some code with gcc (that had previously compiled and run
without complaint under CodeWarrior), the following fatal error was
reported:

Error.h:83: looser throw specifier for `virtual Error::~Error()'
/usr/include/gcc/darwin/3.1/g++-v3/exception:54: overriding
`virtual std::exception::~exception() throw ()'

The error message is completely correct, but deserves some explanation.
It occurs when a method in a derived class has a different throw
specifier (the set of allowed objects that can be thrown from within the
method) to the base class. In the above example, the base class
‘std::exception’ is defined:

class exception {
   ...
   virtual ~exception() throw();
   ...
};

while the derived class ‘Error’ is defined:

class Error: public std::exception {
   ...
   ~Error ();
   ...
};

Note that if no destructor is defined in the derived class, the problem
still occurs as the automatically generated destructor is like that
above, i.e. has no throw specifier. The appearance of this problem can
be unpredictable as not all compilers will worry about this problem.
(The above example was detected by gcc 3, but passed by gcc 2.9 and
CodeWarrior 8.) Also, in the case of ‘std::exception’, not all
implementions of the STL use throw specifiers. In any event, the derived
class must be corrected:

class Error: public std::exception {
   ...
   ~Error ()
      throw ();
   ...
};
  • Forum
  • Beginners
  • Getting Error «looser throw specifier fo

Getting Error «looser throw specifier for `virtual APIEx::~APIEx()'»

Hi I am new to C++. I am getting this error when i am compiing the below piece of code. I am using eclipse Helios IDE for windows 32.

#ifndef APIEX_H_
#define APIEX_H_

#include <exception>

class APIEx: public std::exception {
public:
APIEx();
virtual ~APIEx(); ///Here i am getting this error.[/b]};

#endif

Please advice me what i am missing here.

Thanks in advance.
Ashok Mohanty

Last edited on

try changing it to this:

1
2
3
4
5
class APIEx: public std::exception {
public:
APIEx() throw();
virtual ~APIEx() throw(); 
};

Thanks For your quick reply. But it is still not working. I think i have to explain you everything abt IDE and compiler etc.. I am using below setups.
1. MINGW/MINSys
2. Eclipse Helios IDE for windows.
3. GCC 3.4.5
4. I am adding one class i.e APIEx from new menu .
5. It adds two files i.e APIEx.h and APIEx.cpp

Class APIEX.h
———————————
#ifndef APIEX_H_
#define APIEX_H_

#include <exception>

class APIEx: public std::exception {
public:
APIEx() throw(); //Error- than previous declaration `APIEx::APIEx() throw ()’
virtual ~APIEx() throw(); //Error-than previous declaration `virtual APIEx::~APIEx() throw ()’
};

#endif /* APIEX_H_ */

Class APIEx.CPP
—————————-
#include «APIEx.h»

APIEx::APIEx() {
//Error- declaration of `APIEx::APIEx()’ throws different exceptions

}

APIEx::~APIEx() {
//Error- declaration of `virtual APIEx::~APIEx()’ throws different exceptions
}

Hope i am clear this time.

Thanks
Ashok

The same applies when you define it in the .cpp add throw() right afterwards, so:
Class APIEx.CPP
—————————-

1
2
3
4
5
6
7
8
9
10
#include "APIEx.h"

APIEx::APIEx() throw() {
//Error- declaration of `APIEx::APIEx()' throws different exceptions

}

APIEx::~APIEx() throw() {
//Error- declaration of `virtual APIEx::~APIEx()' throws different exceptions
}

The same applies when you define it in the .cpp add throw() right afterwards, so:
Class APIEx.CPP
—————————-

1
2
3
4
5
6
7
8
9
10
#include "APIEx.h"

APIEx::APIEx() throw() {
//Error- declaration of `APIEx::APIEx()' throws different exceptions

}

APIEx::~APIEx() throw() {
//Error- declaration of `virtual APIEx::~APIEx()' throws different exceptions
}

Thanks..Its solved.

Topic archived. No new replies allowed.

  1. 02-08-2008


    #1

    keira is offline


    Registered User


    looser throw specifier for virtual…

    Hey, here’s the error: «error: looser throw specifier for virtual OutOfMemory::~OutOfMemory
    «
    What does it mean, why does it happen, what do i do to fix? Thanks. (Compiling with GNU compiler)

    Code:

    #include <exception>
    
    using namespace std; 
    
    class OutOfMemory : public std::exception
    {
    	private: 
    		string identification; 
    	
    	public:
    		OutOfMemory(string ident) : identification(ident) {}
    		string what() { return "identification"; }		
    };


  2. 02-08-2008


    #2

    anon is offline


    The larch


    My compiler continues the error message:

    overriding `virtual std::exception::~exception() throw ()’

    Apparently OutOfMemory should have a destructor which promises not to throw, too.

    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.

    Quoted more than 1000 times (I hope).


  3. 02-08-2008


    #3

    keira is offline


    Registered User


    Unhappy

    I’ve never seen a declaration like that before and I don’t really know how to promise things to the compiler


  4. 02-08-2008


    #4

    laserlight is offline


    C++ Witch

    laserlight's Avatar


    Basically, you define:

    Code:

    ~OutOfMemory() throw() {}

    Incidentally, I note that what() returns a const char*, and is const, and apparently also has throw().

    EDIT:
    Interestingly, I do not recall having to bother with this, but then the only exception classes I have written derive from a subclass of std::exception, e.g., std::logic_error. As such, I could use the constructor that takes a string instead of providing my own string member variable.

    I suggest that you do the same.

    Last edited by laserlight; 02-08-2008 at 09:56 AM.

    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)

    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. «Finding the smallest program that demonstrates the error» is a powerful debugging tool.

    Look up a C++ Reference and learn How To Ask Questions The Smart Way


  5. 02-08-2008


    #5

    matsp is offline


    Kernel hacker


    Quote Originally Posted by laserlight
    View Post

    Incidentally, I note that what() returns a const char*, and is const, and apparently also has throw().

    You mean that it SHOULD, because right now it calls the std::string constructor with a constant string. This may well cause a memory exception in itself, if the system is very low on memory, since the string constructor will have to allocate memory to store the string.


    Mats

    Compilers can produce warnings — make the compiler programmers happy: Use them!
    Please don’t PM me for help — and no, I don’t do help over instant messengers.


  6. 02-08-2008


    #6

    laserlight is offline


    C++ Witch

    laserlight's Avatar


    No, it does, since we are talking about a method that is supposed to be overriden. At the moment the what() hides the virtual function inherited.

    This may well cause a memory exception in itself, if the system is very low on memory, since the string constructor will have to allocate memory to store the string.

    I think that is related to the current compile error, though I do not quite understand why it affected the destructor instead of the constructor.

    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)

    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. «Finding the smallest program that demonstrates the error» is a powerful debugging tool.

    Look up a C++ Reference and learn How To Ask Questions The Smart Way


  7. 02-09-2008


    #7

    cpjust is offline


    and the hat of sweating


    Quote Originally Posted by matsp
    View Post

    You mean that it SHOULD, because right now it calls the std::string constructor with a constant string. This may well cause a memory exception in itself, if the system is very low on memory, since the string constructor will have to allocate memory to store the string.


    Mats

    I’m guessing std::terminate() would be called and your program would abort if that happened?


  •  
  • c++

  • compiler-construction

  • xcode

  • gcc

  •  01-10-2019
  •  | 

  •  

Question

I am getting an error that says:

error: looser throw specifier for ‘virtual CPLAT::CP_Window::~CP_Window()’

On the destructor, I have never heard of this before and some Google Searches say this might be a GCC 4 problem, which I would not be sure how to work around since I need GCC 4 to build a Universal Binary.

My Environment: OS X 10.6, XCode 3.2.2, GCC 4 to build a universal binary.

What is the issue?

Solution

I assume that CPLAT has a base class? I’m also guessing that you did not put a throw specifier on CPLAT’s destructor?

You can put throw(X) (where X is a comma-separated list of exceptions) at the end of a function’s signature to indicate what exceptions it’s allowed to throw. If you put throw() as the throw specifier, then it would indicate that no exceptions can be thrown from that function. It’s fairly common to do this with destructors since you don’t ever want a destructor to throw an exception.

A class that overrides a function which has a throw specifier cannot have a looser throw specifier (list more exceptions) than the function being overridden, since that would indicate that the derived class’ function could violate the throw specifier of the base class’ function. Not having a throw specifier means that any exception can be thrown from that function, so it’s as loose as it can get.

In all likelihood, you need to add throw() to the end of the function signature of CPLAT’s destructor.

Edit: By the way, I should probably add that you probably don’t want to use throw specifiers (other than throw() on destructors) without really knowing that that’s what you want. Unlike Java’s checked exceptions, they’re not caught at compile-time but rather terminate your program at runtime if violated. So, it’s best not to use them unless you know what you’re doing.

OTHER TIPS

As the same for the C — Error / Warning section, I made this one to summarize common mistakes when I tried to compile my code.

So let’s go to see some good errors and warnings in C++ (I’m sure it is also a great moment for you when you discovered these errors).

1. Main.cpp:(.text+0x1f): undefined reference to `Parent::Parent()’

A. The problem

A very common error!
Did you include the parent.cpp file in your Makefile?
Did you compile with this parent.cpp?

B. The solution

Add the correct name of the file into the Makefile to compile it with others .cpp files.

SRC= main.cpp parent.cpp

2. Expected class-name before ‘,’ token
/ expected class-name before ‘{’ token

A. The problem

You forgot to include the two headers of the two parent classes needed.

class Child: public Mother, public Father {
public:
    Child();
    ~Child();
};

B. The solution

Include the right files:

#include "father.hh"
#include "mother.hh"

class Child: public Mother, public Father {
public:
    Child();
    ~Child();
};

3. Virtual base ‘Parent’ inaccessible in ‘Child’ due to ambiguity

A. The problem

You have a Child class that inherits from a Mother and a Father class.
These two parents inherit from the Parent class.
But only one of them inherits with the virtual keyword.

// parent.hh
class Parent {
public:
    Parent();
    virtual ~Parent();
};
// mother.hh
#include "parent.hh"

class Mother: virtual public Parent {
public:
    Mother();
    virtual ~Mother();
};
// father.hh
#include "parent.hh"

class Father: public Parent {
public:
    Father();
    virtual ~Father();
};
//child.hh
#include "father.hh"
#include "mother.hh"

class Child: public Mother, public Father {
public:
    Child();
    virtual ~Child();
};

B. The solution

Add the virual keyword before the public parent call.

// father.hh

#include "parent.hh"

class Father: virtual public Parent {
public:
    Father();
    virtual ~Father();
};

4. ‘Parent’ is an ambiguous base of ‘Child’

A. The problem

You have a Child class that inherits from a Mother and a Father class.
These two parents inherit from the Parent class.
But neither the Mother nor the Father inherits from the Parent with the virtual keyword.

This is the diamond problem because we have a Child that inherits from two classes (Mother and Father) that both inherit from a Parent.
The compiler doesn’t know which class called because without the virtual keyword, it creates the class Parent twice.
And we have then two inheritance trees.

// parent.hh
class Parent {
public:
    Parent();
    virtual ~Parent();
};
// mother.hh
#include "parent.hh"

class Mother: public Parent {
public:
    Mother();
    virtual ~Mother();
};
// father.hh
#include "parent.hh"

class Father: public Parent {
public:
    Father();
    virtual ~Father();
};
//child.hh
#include "father.hh"
#include "mother.hh"

class Child: public Mother, public Father {
public:
    Child();
    virtual ~Child();
};

B. The solution

Add the virual keyword before the public parent call.
The compiler will now creates only one instance of the Parent class, and links the both children (Father and Mother) to the same memory area of the unique Parent.

// father.hh
#include "parent.hh"

class Father: virtual public Parent {
public:
    Father();
    virtual ~Father();
};
// mother.hh
#include "parent.hh"

class Mother: virtual public Parent {
public:
    Mother();
    virtual ~Mother();
};

5.  Constructor.cpp:(.text+0x14): undefined reference to `vtable for Constructor’

A. The problem

This problem may be different things.

For example it may missing something. The Constructor is there but the Destructor isn’t.

B. The solution

Implementing the Destructor.

6. error: variable ‘std::ifstream ifile’ has initializer but incomplete type

A. The problem

You forgot to include <fstream>. 

B. The solution

Include it:

#include <fstream>

7. error: expected primary-expression before ‘<<’ token

A. The problem

You certainly use a semicolon before the end of the function. 

Exemple:

std::cout << typeInt->getType(); << std::endl;

B. The solution

Remove it:

std::cout << typeInt->getType() << std::endl;

8. error: lvalue required as left operand of assignment

A. The problem

The asterisk (*) is not put at the right place. 

Exemple:

You are using an iterator i and you want to put the 8 value inside the value before the current iterator.
So you try to do:

(*i - 1) = 8;

B. The solution

Change the place if the asterisk before the right parenthesis.

*(i - 1) = 8;

9. error: looser throw specifier for ‘virtual MyClass::~MyClass()’
error:   overriding ‘virtual MyException::~MyException() throw ()’

A. The problem

In the derived class from std::exception, we have the following destructor:

virtual ~MyException() throw();

B. The solution

Add the same prototype destructor to your derived class from MyException.

virtual ~MyClass() throw();
Автор Тема: Зачем в данном коде виртуальный диструктор и throw()?  (Прочитано 9518 раз)
8Observer8

Гость


Привет! У меня есть такой код:

C++ (Qt)

class LogicError : public std::logic_error {
public:

     LogicError( ) : std::logic_error( "" ) {

     }

     virtual const char *what( ) const throw( ) {
       return m_message.c_str( );
   }

     virtual ~LogicError( ) throw( ) {

     }

 protected:
   std::string m_message;
};

Поясните, пожалуйста, почему компилятор требует:
1) Виртуальный деструктор
2) Наличие throw() в виртуальном деструкторе
3) Наличие throw() в методе what( )


Записан
Vamireh

Гость


потому что они перегружаются из класса logic_error и требуют точного соблюдения сигнатуры


Записан
8Observer8

Гость


Спасибо за ответ! Я так понял, что надо было мне смотреть на базовый класс под названием std::exception. А std::logic_error наследует what() и виртуальный деструктор: http://www.cplusplus.com/reference/exception/exception/

Причём компилятор заставляет переопределять виртуальный деструктор и пишет:

looser throw specifier for ‘virtual LogicError::~LogicError()’
 class LogicError : public std::logic_error {
        ^

И я понял — почему. Если бы мы «понадеялись» на деструктор базового класса, то LogicError не был бы полностью уничтожен.

Вот только не могу понять, почему std::logic_error не переопределяет виртуальный деструктор? http://www.cplusplus.com/reference/stdexcept/logic_error/

« Последнее редактирование: Май 20, 2014, 05:36 от 8Observer8 »
Записан
OKTA

Гость


Просто виртуальные методы (в отличии от чисто виртуальных) не обязательно переопределять — можно воспользоваться реализацией по-умолчанию, которая наследуется от предка. Но если мы все же хотим переопределить метод, то он должен полностью соответствовать родительскому по сигнатуре.

« Последнее редактирование: Май 20, 2014, 09:33 от OKTA »
Записан
8Observer8

Гость


С методами — да. А вот получается из примера выше, что виртуальный деструктор обязательно надо переопределять, хотя он и не чисто виртуальный.

Вопрос: почему std::logic_error не переопределяет виртуальный деструктор базового класса std::exception? http://www.cplusplus.com/reference/stdexcept/logic_error/

P.S. Хотя может просто не написали в справке. Либо я что-то не понимаю.


Записан
OKTA

Гость


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

« Последнее редактирование: Май 20, 2014, 09:59 от OKTA »
Записан
OKTA

Гость


Вот в таком случае деструктор надо обязательно переопределять

class A {
public:
    virtual ~A() = 0;

};
A::~A() {
    qDebug() << «Destroy A»;
}

class B : public A {
public:
    ~B() {
        qDebug() << «Destroy B»;
    }

};


Записан
8Observer8

Гость


Он мне выдаёт ошибку, если я не переопределяю.


Записан
OKTA

Гость


А какой компилятор?? Даже такой код не компилируется?  Непонимающий

class A : public std::logic_error{

};


Записан
8Observer8

Гость


Компилятор — тот что идёт со сборкой: … for Windows 32-bit (MinGW 4.8.2, OpenGL)

Если в следующем примере раскомментировать код, то всё работает, с комментариями — нет.

Говорит, что:

main.cpp:6: error: looser throw specifier for ‘virtual LogicError::~LogicError()’
 class LogicError : public std::logic_error {
        ^

C++ (Qt)

 
#include <stdexcept>
#include <string>
#include <iostream>

 class LogicError : public std::logic_error {
public:

     LogicError( ) : std::logic_error( "" ) {

     }

     virtual const char *what( ) const throw( ) {
       return m_message.c_str( );
   }

 /*
   virtual ~LogicError( ) throw( ) {

     }
*/

 protected:
   std::string m_message;
};

 class EmptyArgument : public LogicError {
public:

     EmptyArgument( ) {
       m_message = "Error: empty argument";
   }
};

 void printText( const std::string &text ) throw( EmptyArgument ) {

     if( text.empty( ) ) {
       throw EmptyArgument( );
   }

     std::cout << text << std::endl;
}

 int main() {
   std::string text = "Hello, World!";

     try {
       printText( text );
   } catch( const LogicError &e ) {
       std::cerr << e.what() << std::endl;
   } catch( ... ) {
       std::cerr << "Error: unknown exception" << std::endl;
   }

     return 0;
}

« Последнее редактирование: Май 20, 2014, 13:51 от 8Observer8 »
Записан
OKTA

Гость


Хм, дело вижу в std::string m_message;  Но вот почему, я не знаю, нужна помощь более опытных   Улыбающийся


Записан
OKTA

Гость


An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions.

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

« Последнее редактирование: Май 20, 2014, 12:47 от OKTA »
Записан
8Observer8

Гость


А какие функции тут генерируют исключения? Такая запись throw( ) после метода означает, что он не будет генерировать никаких исключений.


Записан
OKTA

Гость


деструктор в std::string я думаю генерирует исключения.


Записан
m_ax

Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2080

Просмотр профиля


деструктор в std::string я думаю генерирует исключения.

Дело не в том, генерирует или не генерирует  он исключения, а в том, что он (деструктор std::string) объявлен без throw(), в то время как деструктор LogicError однозначно исключения кидать не должен (семантика деструктора наследника должна совпадать с семантикой родителя). 
Можете проверить это, заменив string на свой пользовательский тип с пустым деструктором, который точно ничего не кидает, но без throw().. Будет таже самая ситуация, что и со string.
 


Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5

Понравилась статья? Поделить с друзьями:
  • Error looking up domain users wbinfo
  • Error loading shared library ld linux x86 64 so 2 no such file or directory
  • Error loading shared libraries civilization 4
  • Error loading shader libraries civilization 4
  • Error loading server extension jupyterlab