함수의 서명에 키워드를 던져
throw
함수 시그니처에 C ++ 키워드 를 사용하는 것이 좋지 않은 것으로 간주되는 기술적 이유는 무엇입니까 ?
bool some_func() throw(myExc)
{
...
if (problem_occurred)
{
throw myExc("problem occurred");
}
...
}
아니요, 모범 사례로 간주되지 않습니다. 반대로, 그것은 일반적으로 나쁜 생각으로 간주됩니다.
http://www.gotw.ca/publications/mill22.htm 이유에 대해 더 자세히 설명하지만 문제는 부분적으로 컴파일러가이를 강제 할 수 없기 때문에 런타임에 검사해야한다는 것입니다. 탐탁지 않은. 그리고 어떤 경우에도 잘 지원되지 않습니다. MSVC는 throw ()를 제외하고 예외 사양이 무시되며 예외가 발생하지 않는다는 보장으로 해석됩니다.
Jalf는 이미 그것에 연결되어 있지만 GOTW 는 예외 사양이 원하는 것만 큼 유용하지 않은 이유를 꽤 잘 설명했습니다.
int Gunc() throw(); // will throw nothing (?)
int Hunc() throw(A,B); // can only throw A or B (?)
의견이 맞습니까? 좀 빠지는.
Gunc()
실제로 무언가를 던질Hunc()
수 있으며 A 또는 B 이외의 것을 던질 수도 있습니다! 컴파일러는 그렇게 할 경우 무의식적으로 이기고… 오, 대부분의 경우 무의식적으로 프로그램을이기는 것을 보증합니다.
그것은 단지 그것이 내려 오는 것입니다. 아마도 당신은 아마도 호출 terminate()
하지만 당신의 프로그램은 빠르고 고통스러운 죽음을 죽게 될 것입니다.
GOTW의 결론은 다음과 같습니다.
다음은 오늘날 커뮤니티로서 우리가 배운 최고의 조언 인 것 같습니다.
- 도덕적 # 1 : 예외 사양을 쓰지 마십시오.
- 도덕적 # 2 : 아마도 비어있는 것을 제외하고, 내가 당신이라면 나는 그것조차 피할 것입니다.
이 질문에 대한 다른 모든 답변에 약간의 가치를 더하려면 몇 분 동안 질문에 투자해야합니다. 다음 코드의 결과는 무엇입니까?
#include <iostream>
void throw_exception() throw(const char *)
{
throw 10;
}
void my_unexpected(){
std::cout << "well - this was unexpected" << std::endl;
}
int main(int argc, char **argv){
std::set_unexpected(my_unexpected);
try{
throw_exception();
}catch(int x){
std::cout << "catch int: " << x << std::endl;
}catch(...){
std::cout << "catch ..." << std::endl;
}
}
답 : 여기 에 언급 된 바와 같이 , 프로그램은 호출 std::terminate()
되므로 예외 핸들러는 호출 되지 않습니다.
세부 사항 : 첫 번째 my_unexpected()
함수가 호출되지만 throw_exception()
함수 프로토 타입에 대해 일치하는 예외 유형이 다시 발생하지 않으므로 결국 std::terminate()
호출됩니다. 따라서 전체 출력은 다음과 같습니다.
user @ user : ~ / tmp $ g ++ -o except.test except.test.cpp
user @ user : ~ / tmp $ ./except.test
잘-이것은
'int'인스턴스를 던진 후에 호출 이 예기치 않게 종료되었습니다
(코어 버려진)
The only practical effect of the throw specifier is that if something different from myExc
is thrown by your function, std::unexpected
will be called (instead of the normal unhandled exception mechanism).
To document the kind of exceptions that a function can throw, I typically do this:
bool
some_func() /* throw (myExc) */ {
}
Well, while googling about this throw specification, I had a look at this article :- (http://blogs.msdn.com/b/larryosterman/archive/2006/03/22/558390.aspx)
I am reproducing a part of it here also, so that it can be used in future irrespective of the fact that the above link works or not.
class MyClass
{
size_t CalculateFoo()
{
:
:
};
size_t MethodThatCannotThrow() throw()
{
return 100;
};
void ExampleMethod()
{
size_t foo, bar;
try
{
foo = CalculateFoo();
bar = foo * 100;
MethodThatCannotThrow();
printf("bar is %d", bar);
}
catch (...)
{
}
}
};
When the compiler sees this, with the "throw()" attribute, the compiler can completely optimize the "bar" variable away, because it knows that there is no way for an exception to be thrown from MethodThatCannotThrow(). Without the throw() attribute, the compiler has to create the "bar" variable, because if MethodThatCannotThrow throws an exception, the exception handler may/will depend on the value of the bar variable.
In addition, source code analysis tools like prefast can (and will) use the throw() annotation to improve their error detection capabilities - for example, if you have a try/catch and all the functions you call are marked as throw(), you don't need the try/catch (yes, this has a problem if you later call a function that could throw).
When throw specifications were added to the language it was with the best intentions, but practice has borne out a more practical approach.
With C++, my general rule of thumb is to only use throw specifications to indicate that a method can't throw. This is a strong guarantee. Otherwise, assume it could throw anything.
A no throw specification on an inlined function that only returns a member variable and could not possibly throw exceptions may be used by some compilers to do pessimizations (a made-up word for the opposite of optimizations) that can have a detrimental effect on performance. This is described in the Boost literature: Exception-specification
With some compilers a no-throw specification on non-inline functions may be beneficial if the correct optimizations are made and the use of that function impacts performance in a way that it justifies it.
To me it sounds like whether to use it or not is a call made by a very critical eye as part of a performance optimization effort, perhaps using profiling tools.
A quote from the above link for those in a hurry (contains an example of bad unintended effects of specifying throw on an inline function from a naive compiler):
Exception-specification rationale
Exception specifications [ISO 15.4] are sometimes coded to indicate what exceptions may be thrown, or because the programmer hopes they will improve performance. But consider the following member from a smart pointer:
T& operator*() const throw() { return *ptr; }
This function calls no other functions; it only manipulates fundamental data types like pointers Therefore, no runtime behavior of the exception-specification can ever be invoked. The function is completely exposed to the compiler; indeed it is declared inline Therefore, a smart compiler can easily deduce that the functions are incapable of throwing exceptions, and make the same optimizations it would have made based on the empty exception-specification. A "dumb" compiler, however, may make all kinds of pessimizations.
For example, some compilers turn off inlining if there is an exception-specification. Some compilers add try/catch blocks. Such pessimizations can be a performance disaster which makes the code unusable in practical applications.
Although initially appealing, an exception-specification tends to have consequences that require very careful thought to understand. The biggest problem with exception-specifications is that programmers use them as though they have the effect the programmer would like, instead of the effect they actually have.
A non-inline function is the one place a "throws nothing" exception-specification may have some benefit with some compilers.
참고URL : https://stackoverflow.com/questions/1055387/throw-keyword-in-functions-signature
'IT' 카테고리의 다른 글
ASP.NET ID DbContext 혼란 (0) | 2020.05.16 |
---|---|
왜 파이썬 메소드에 "self"인수가 명시 적으로 필요합니까? (0) | 2020.05.16 |
삼항 연산자로 허용되지만 if 문이 아닌 정수로 null을 반환 (0) | 2020.05.16 |
ListBox와 ListView의 차이점은 무엇입니까 (0) | 2020.05.16 |
SSH를 통해 Eclipse로 원격 프로젝트 작업 (0) | 2020.05.16 |