Construct object by calling constructor (method) explicitly
Definition of class:
#pragma once
#include <string>
#include <utility>
namespace impress_errors {
#define BUFSIZE 512
class Error {
public:
Error(int number);
Error(std::string message);
Error(const char *message);
bool IsSystemError();
std::string GetErrorDescription();
private:
std::pair <int, std::string> error;
char stringerror[BUFSIZE]; // Buffer for string describing error
bool syserror;
};
} // namespace impres_errors
I have some piece of code in file posix_lib.cpp:
int pos_close(int fd)
{
int ret;
if ((ret = close(fd)) < 0) {
char err_msg[4096];
int err_code = errno;
throw impress_errors::Error::Error(err_code); //Call constructor explicitly
}
return ret;
}
And in another file fs_creation.cpp:
int FSCreation::GenerateFS() {
int result;
try {
result = ImprDoMakeTree(); //This call pos_close开发者_JS百科 inside.
}
catch (impress_errors::Error error) {
logger.LogERROR(error.GetErrorDescription());
return ID_FSCREATE_MAKE_TREE_ERROR;
}
catch (...) {
logger.LogERROR("Unexpected error in IMPRESSIONS MODULE");
return ID_FSCREATE_MAKE_TREE_ERROR;
}
if(result == EXIT_FAILURE) {
return ID_FSCREATE_MAKE_TREE_ERROR;
}
return ID_SUCCESS;
}
On my version of compiler this one is compiled and work correct:
g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 (Ubuntu Maverick - 10.04) On another version of compiler: g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 (Ubuntu Narwhal - 11.04) it causes error: posix_lib.cpp: In function ‘int pos_close(int)’: posix_lib.cpp:363:46: error: cannot call constructor ‘impress_errors::Error::Error’ directly posix_lib.cpp:363:46: error: for a function-style cast, remove the redundant ‘::Error’ Questions: 1. Why this work on one version of g++, and failed on another? 2. What happens when I explicitly call constructor for creating object? Is it correct? And why this is working?You are not calling the constructor (well, you are, but not in the way you mean it). The syntax ClassName(constructor params)
means to create a temporary object of the type ClassName
, using the given parameters for its constructor. So you aren't simply calling the constructor; you are creating an object.
So you are creating an Error
object. Your problem is that the name of Error
is impress_errors::Error
, not "impress_errors::Error::Error". The second ::Error
would seem to be an attempt to name the constructor. Constructors don't have names; they are not functions that you can find and call at your whim (again, not in the way you mean it).
This looks like an error in the compiler which rejects it. The code is
legal, but not for the reasons you think. There is no such thing as
"calling constructor (method) explicitly", because constructors don't
have names (§12.1/1). On the other hand, impress_errors::Error::Error
is the name of a type; class name injection (§9/2) means that the class
impress_errors::Error
contains a declaration of the name Error
in
the class, as a synonym for the name outside of the class. So
impress_errors::Error
, impress_errors::Error::Error
,
impress_errors::Error::Error::Error
, etc. all name the same type
(although only the first is idiomatic—the rest are all just extra
noise). And when the name of a type is followed by a parenthesized
expression list, as is the case here, it is an "Explicity type
conversion (functional notation)". (§5.2.3—and the standard says it
is an explicit type conversion even if the expression list is empty, or
contains more than one expression—don't ask me what "type" is
being converted in such cases.) So impress_errors::Error(err_code)
(or
impress_errors::Error::Error(err_code)
means convert err_code
into
an impress_errors::Error
. Which, in this case, will result in calling
the constructor, since that's the only way to convert an int
into an
impress_errors::Error
. (It's possible, however, to construct cases
where the compiler will call a user defined conversion function on the
object being converted.)
It should be ok if You do what compiler is asking You. Just remove one "Error" statement;> I'm not sure why this changed in gcc, but class_name::construction_name is just redundant. Compiler knows that You want to call constructor, because its name is the same as the name of the class
While you could explicitly call the constructor using placement new, see placement operators, you don't have an object or piece of memory in which to place the object yet. Probably easier to use something like
throw new MyError(MyParams);
and make the exception handler responsible for deleting it. FWIW Microsoft use this approach with MFC.
I ran into the exact same error message.
The solution is to change this line:
throw impress_errors::Error::Error(err_code); //Call constructor explicitly
to
throw impress_errors::Error(err_code); //Call constructor explicitly
In C++ you can call the base class constructor inside a derived class constructor, just never use the scope resolution operator ::
精彩评论