2012-06-23 52 views
2

我的代码中有一个样式问题,我不知道其他人是否遇到过。 假设我有一个没有默认构造函数的类,或者有一个我不想调用的默认构造函数(出于性能和样式的原因)。为了举例,假设这是一个File对象。变量声明捕获异常

现在,让我们说,我有一个包含文件名来删除...列表的文件,我要做到以下几点:

File f("foo"); 
for (const string& filenameToDelete : f.Lines()) 
    File(filenameToDelete).Delete(); 

文件可以在构造或删除功能抛出FileNotFound 。我的代码必须首先抛出删除文件失败,但如果文件“foo”不存在则不得抛出(文件不存在就意味着不需要删除)。

我希望我能写这样的事:

try { File f("foo"); } catch (FileNotFound) { return; } 
for (const string& filenameToDelete : f.Lines()) 
    File(filenameToDelete).Delete(); 

但这显然不能编译。 我可以这样做:

unique_ptr<File> f; 
try { f.reset(new File("foo")); } catch (FileNotFound) { return; } 
for (const string& filenameToDelete : f->Lines()) 
    File(filenameToDelete).Delete(); 

,但我不喜欢有些事实,我需要为原本可以堆栈分配的变量做内存分配...

如果我想编写代码与我不做堆分配的有点武断约束,我只能想到做这样的:

struct FileNotFoundToRethrow : public FileNotFound {}; 
try 
{ 
    File f("foo"); 
    try 
    { 
     for (const string& filenameToDelete : f.Lines()) 
      File(filenameToDelete).Delete(); 
    } 
    catch (FileNotFound) 
    { 
     throw FileNotFoundToRethrow(); 
    } 
} 
catch (FileNotFoundToRethrow) { throw; } 
catch (FileNotFound) { return; } 

我觉得这是很丑陋,很难看到所有我想要做的就是处理第一行抛出的FileNotFound异常...有更好的方法吗?

+0

为什么你坚持写作'文件(filenameToDelete).Delete()'作为一个单独的语句?如果你把它分成'File foo(filenameToDelete)'和'foo.Delete()',看起来你可以做你想做的事。 – jjlin

+0

我写他们作为一个单一的陈述主要是为了尽可能短的例子(为了节省读者的时间)。我不确定我看到如何将两条线分开对我的情况有所帮助。 – anonymous

+0

_Boost.Optional_将像'unique_ptr'一样工作,除非不需要分配。 –

回答

1

我会做一个标志

bool throwOnNotFound = false; 

try 
{ 
    File f("foo"); 

    throwOnNotFound = true; 

    for (const string& filenameToDelete : f.Lines()) 
     File(filenameToDelete).Delete(); 
} 
catch (FileNotFound) 
{ 
    if (throwOnNotFound) 
     throw; 
} 
+0

你说得对,它比我定义的一个新的异常类型更清洁!我仍然不喜欢catch块离我们想要处理异常的线路很远...... – anonymous

1

有可能为所有那些谁觉得特别智者,extending the lifetime with reference to const的方式。但是有缺点。一个类必须有一个空(或默认)对象,而且,引用是const。使用它

File fooFile() 
{ 
    try { return File("foo"); } catch (FileNotFound) { return File::Default; } 
} 

const File& foo = fooFile(); 

if (foo.IsDefault()) 
    return; 

for (const string& filenameToDelete : f.Lines()) 
     File(filenameToDelete).Delete();