I want to open a file in a class constructor. 几乎肯定是个坏主意。在构建过程中打开文件的情况很少是合适的。 It is possible that the opening could fail, then the object construction could not be completed. How to handle this failure? Throw exception out? 是的,就是这样。 If this is possible, how to handle it in a non-throw constructor? 使类的完全构造的对象可能无效。这意味着提供验证例程,使用它们,等等。
8条答案
按热度按时间lsmepo6l1#
如果对象构造失败,则引发异常。
另一种选择是可怕的。如果构造成功,您必须创建一个标志,并在每个方法中检查它。
cu6pst1q2#
我想在类构造函数中打开一个文件。可能的是,开口可能失败,然后对象构造不能完成。该如何处理这种失败?抛出异常?
是的
如果可能,如何在非抛出构造函数中处理它?
您的选项包括:
*重新设计应用程序,使其不需要构造函数是非抛出的-真的,如果可能的话,就这么做
if (X x) ...
(即对象可以在布尔上下文中求值,通常通过提供operator bool() const
或类似的整数转换),但是你没有x
的作用域来查询错误的详细信息。这可能是熟悉的,例如。if (std::ifstream f(filename)) { ... } else ...;
bool worked; X x(&worked); if (worked) ...
if (X* p = x_factory()) ...
</li> <li>
X x;//永远不可用; if(init_x(&x))...`简而言之,C++旨在为这些问题提供优雅的解决方案:在这种情况下例外。如果你人为地限制自己使用它们,那么不要指望有其他东西能做到一半好。
(P.S.我喜欢传递变量,将被指针修改-根据
worked
上面-我知道FAQ精简版不鼓励它,但不同意推理。我对这方面的讨论并不特别感兴趣,除非你有一些FAQ没有涉及的问题。)4urapxun3#
新的C++标准在很多方面重新定义了这个问题,是时候重新审视这个问题了。
最佳选择:
static std::experimental::optional<T> construct(...)
。后者尝试设置成员字段,确保不变,并且只有在确定成功的情况下才调用私有构造函数。私有构造函数仅填充成员字段。测试可选代码很容易,而且价格便宜(在一个好的实现中,甚至可以省去副本)。if
。好的选择:
.build()
方法来构造另一个类。如果builder是friend,constructor可以是private。它甚至可能需要一些只有builder才能构造的东西,这样就可以证明这个构造函数只能由builder调用。糟糕的选择:(但看过很多次)
optional<>
。想想optional<T>
可以是无效的,T
不能。仅对有效对象起作用的(成员或全局)函数对T
起作用。一个肯定返回有效的方法适用于T
。一个可能返回无效对象的方法返回optional<T>
。一个可能使对象无效的方法取nonconstoptional<T>&
或optional<T>*
。这样,你就不需要检查每个函数来证明你的对象是有效的(而那些if
可能会变得有点昂贵),但是在构造函数上也不会失败。init()
*:这并不比返回optional<>
的函数更好,但需要两个构造,并打乱了你的不变量。bool& succeed
*:这就是我们在optional<>
之前所做的。optional<>
优越的原因是,你不能错误地(或不小心!)忽略succeed
标志并继续使用部分构造的对象。示例:
kxkpmulp4#
对于这种情况,我的建议是,如果你不想让一个构造器因为无法打开文件而失败,那么就避免这种情况。向构造函数传递一个已经打开的文件,如果这是你想要的,那么它就不会失败...
zdwk9cvp5#
一种方法是抛出异常。另一种方法是有一个'bool is_open()'或'bool is_valid()'函数,如果构造函数出错,则返回false。
这里的一些注解说在构造函数中打开文件是错误的。我要指出的是,ifstream是C++标准的一部分,它有以下构造函数:
它不会抛出异常,但它有一个is_open函数:
jaql4c8m6#
I want to open a file in a class constructor.
几乎肯定是个坏主意。在构建过程中打开文件的情况很少是合适的。
It is possible that the opening could fail, then the object construction could not be completed. How to handle this failure? Throw exception out?
是的,就是这样。
If this is possible, how to handle it in a non-throw constructor?
使类的完全构造的对象可能无效。这意味着提供验证例程,使用它们,等等。
cwtwac6a7#
构造函数可以打开一个文件(不一定是个坏主意),如果文件打开失败,或者如果输入文件不包含兼容的数据,则可能会抛出。
构造函数抛出异常是合理的行为,但是您将受到其使用的限制。
您可以通过使对象处于“失败”状态来处理它,而不会出现异常。这是在不允许抛出的情况下必须执行的方法,当然,您的代码必须检查错误。
pgvzfuti8#
使用工厂。
工厂可以是一个完整的工厂类“
Factory<T>
”,用于构建“T
”对象(它不一定是模板),也可以是“T
”的静态公共方法。然后,您将构造函数设置为受保护,并将析构函数保留为公共。这确保了新类仍然可以从“T
”派生,但除了它们之外,没有外部代码可以直接调用构造函数。使用工厂方法(C++17)
与设置“有效”位或其他黑客不同,这是相对干净和可扩展的。如果做得好,它可以保证没有无效对象会逃逸到野外,并且编写派生的'Foo'仍然很简单。由于工厂函数是普通函数,所以你可以用它们做很多构造函数不能做的事情。
在我的拙见中,你永远不应该把任何可能实际失败的代码放入构造函数中。这几乎意味着任何做I/O或其他“真实的工作”的东西。构造函数是语言中的一个特殊情况,它们基本上缺乏处理错误的能力。