Reputation: 1029
I am working on a dialog that requests a file, username, and password from a user. I want the user to be notified when there is an issue with their selection. The file must be valid before I bother checking the name and password fields of my dialog. I know there are other ways to do this, my question is in regards to the efficiency of this process.
My MFC C++ application has a string table where the strings are identified using macros that map a translation unit to an integer (#define IDS_SOME_ERROR 100
), where these integers can be used by the MFC framework to load a string from the string table.
I am curious about the efficiency of throwing primitive types, so I looked into the throw
keyword on cpprefrence.com.
The
throw expression
statement copy-initializes the exception object from expression (this may call the move constructor for rvalue expression, and the copy/move may be subject to copy elision), then transfers control to the exception handler with the matching type whose compound statement or member initializer list was most recently entered and not exited by this thread of execution. Even if copy initialization selects the move constructor, copy initialization from lvalue must be well-formed, and the destructor must be accessible (since C++14).
Here is another question asking about types to throw, I noticed a comment saying not to throw things like int
or string
. Why is this?
Here is my code:
void SomeDialog::OnOK()
{
UpdateData();
try
{
if (VerifySomeFile(myFileStruct.getPath()))
{
if (DialogNameField.IsEmpty())
{
throw IDS_ERROR_NOID; // "No name specified."
}
if (DialogPasswordField.IsEmpty())
{
throw IDS_ERROR_NOPWD; // "No password specified."
}
CDialog::OnOK();
}
else
{
throw IDS_BAD_FILE; // "Bad or expired file."
}
}
catch (int errIDS)
{
CString tempStr;
tempStr.LoadString(errIDS);
AfxMessageBox(tempStr, MB_OK);
}
}
Since an int
is a primitive type in C++, does the throw
statement still have to perform any copying? Is it safe to throw primitive types in C++ in this fashion? Would it be more efficient to remove the catch block and place my error dialog logic from the catch
block to each throw location? If I were to do this, I would also have to nest my code such that only one dialog is shown if there is more than one error.
Upvotes: 2
Views: 1982
Reputation: 62613
Let's begin with getting terminology right. C++ doesn't have a concept of a primitive type. In C++, there are built-in types and custom types.
int
, for this matter, is a built-in type. While from the language perspective throwing an object of type int
is no different from throwing an object of type MySpecialClass
or a derivation of std::exception
, throwing the latter has as a benefit - since this is a well-known exception, one might expect that there would be catch (const std::exception& e)
somewhere in the program. This catch will handle all derivations of std::exception
, and would be possible, at the bare minimum, to print the message within the exception.
However, it is not reasonable to expect one to catch an int
! And even if one does, what next? How this exception is supposed to be handled? Number printed to the console? And what the user should make of it?
Upvotes: 0
Reputation: 117
I would say it would be better to do something like that instead of throwing built-in type:
struct SomeError{int errid};
...
throw SomeError{IDS_BAD_FILE};
Upvotes: 0
Reputation: 1
You shouldn't be worried about efficiency too much, since the recommended practice to catch std::exeption
derivates is to use a const
reference anyways.
It has the advantage to introduce an exception hierarchy, and provide overridden error messages using const char* std::exception::what() const
.
Upvotes: 3