这似乎是一个微不足道的问题,但我现在已经挂了几个小时了(也许是Java太多了我的C ++ braincells)。
我创建了一个具有以下构造函数的类(即没有默认构造函数)
VACaptureSource::VACaptureSource( std::string inputType, std::string inputLocation ) {
if( type == "" || location == "" ) {
throw std::invalid_argument("Empty type or location in VACaptureSource()");
}
type = inputType;
location = inputLocation;
// Open the given media source using the appropriate OpenCV function.
if( type.compare("image") ) {
frame = cvLoadImage( location.c_str() );
if( !frame ) {
throw std::runtime_error("error opening file");
}
}
else {
throw std::invalid_argument("Unknown input type in VACaptureSource()");
}
}
当我想创建一个实例时,我使用
// Create input data object
try {
VACaptureSource input = VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
}
catch( invalid_argument& ia ) {
cerr << "FD Error: " << ia.what() << endl;
usage(argv[0]);
}
catch( runtime_error& re ) {
cerr << "FD Error: " << re.what() << endl;
usage(argv[0]);
}
但是,在这种情况下,实例是此块的本地实例,我无法在其他任何地方引用它。另一方面,我不能说
VACAptureSource input;
在程序开头,因为没有默认构造函数。
这样做的正确方法是什么?
谢谢!
答案 0 :(得分:11)
为什么你需要在try
区块之外引用它?
而不是
try {
VACaptureSource input = VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
}
//catch....
//do stuff with input
您可以将所有内容移动到try块中:
try {
VACaptureSource input = VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
//do stuff with input
}
//catch....
或者您可以将它分解为一个单独的函数,该函数从try块调用:
void doStuff(VACaptureSource& input){
//do stuff with input
}
try {
VACaptureSource input = VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
doStuff(input);
}
//catch....
最后一个甚至为您提供了将构造与使用分开的好处,它可以很好地放入单元测试中,您可能希望函数在模拟对象上工作。
答案 1 :(得分:8)
使用指针(或其某些RAII版本)怎么样?
VACaptureSource* input = NULL;
try {
input = new VACaptureSource(...);
} catch(...) {
//error handling
}
//And, of course, at the end of the program
delete input;
答案 2 :(得分:4)
一个局部变量的范围限定在它所分配的块中(如Java),但是一旦块结束它就会破坏(与Java不同)所以你应该在try块本身中做你想要的所有东西(如果你只想处理构造函数异常,这可能是不可取的,或者你应该在其他地方(例如堆)分配对象,并使用父块中的指针来访问它。
答案 3 :(得分:3)
我可以观察到任何,但是最琐碎的构造函数可能会引发异常。因此,您不应该在某种意义上将异常视为“特殊”,而是编写代码以便自然处理它们。这意味着使用RAII以及此处其他答案提出的其他技术。
答案 4 :(得分:2)
您可以使用指针
VACaptureSource* input;
// Create input data object
try {
input = new VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
}
catch( invalid_argument& ia ) {
cerr << "FD Error: " << ia.what() << endl;
usage(argv[0]);
}
catch( runtime_error& re ) {
cerr << "FD Error: " << re.what() << endl;
usage(argv[0]);
}
当你完成使用它时你需要释放对象
delete input
答案 5 :(得分:2)
我不能说
VACaptureSource input;
在程序开头,因为没有默认的构造函数。
有一个很好的理由你没有创建默认构造函数:即VACaptureSource
仅在与文件关联时才有意义。所以不要创建默认构造函数。而只是简单地认识到VACaptureSource
对象的范围是try
块,并在那里使用它。
答案 6 :(得分:1)
添加一个使对象处于特殊的未配置状态的默认构造函数怎么样?然后有一个create()函数来实际创建它。
然后你可以这样做:
VACaptureSource input;
try
{
input.create("image", "...");
}
catch(...)
{
...
}
根据情况,这可能比弄乱指针更好。虽然那时你还需要在做某事之前检查是否实际调用了create()......
答案 7 :(得分:1)
我实际上看不到任何问题:
我要更新的一些事情:
所以我会这样做(为了清楚起见)。
VACaptureSource::VACaptureSource( std::string const& inputType,
std::string const& inputLocation )
:type(inputType)
,location(inputLocation)
{
// Other Code that throws.
}
void playWithCode()
{
// Get input information from user.
VACaptureSource input("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
// use the input object.
// Do not need to play with pointers here.
}
int main()
{
try
{
playWithCode();
}
catch( invalid_argument const& ia )
{ cerr << "FD Error: " << ia.what() << endl;
usage(argv[0]);
}
catch( runtime_error const& re )
{ cerr << "FD Error: " << re.what() << endl;
usage(argv[0]);
}
}
答案 8 :(得分:0)
简单。不要在构造函数中抛出异常。你不仅需要在try块中包装构造函数,在捕获异常时你将无法很好地处理内存(你是否调用了析构函数?需要删除多少类的内存? )
UPDATE0 :虽然如果您使用实例,我不确定内存管理是否有问题。
UPDATE1 :嗯,也许我正在考虑析构函数中的异常。
int
main2(int argc, char* argv[])
{
MyClass class;
class.doSomething();
}
int
main(int argc, char* argv[])
{
int result = 0;
try {
main2(argc, argv);
} catch (std::exception& se) {
// oh noes!
result = 1;
}
return result;
}