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()
asked Mar 27, 2014 at 20:36
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
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:
|
|
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
—————————-
|
|
The same applies when you define it in the .cpp add throw() right afterwards, so:
Class APIEx.CPP
—————————-
|
|
Thanks..Its solved.
Topic archived. No new replies allowed.
-
02-08-2008
#1
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"; } };
-
02-08-2008
#2
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).
-
02-08-2008
#3
Registered User
I’ve never seen a declaration like that before and I don’t really know how to promise things to the compiler
-
02-08-2008
#4
C++ Witch
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.
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
-
02-08-2008
#5
Kernel hacker
Originally Posted by laserlight
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.
—
MatsCompilers 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.
-
02-08-2008
#6
C++ Witch
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.
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
-
02-09-2008
#7
and the hat of sweating
Originally Posted by matsp
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.
—
MatsI’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 раз) |
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||