【发布时间】:2017-05-30 13:38:32
【问题描述】:
我相信从构造函数体内抛出 *this 是合法的。我想知道我对此是否完全错误(在对象的构造函数完成之前传递对象的问题?)或者这在风格上是否令人厌恶。
我发布了第二个更具体的问题here,该问题已得到全面解答。这篇文章中的代码是合法的,如果有点奇怪的话。
给定一个异常结构:
struct fail final : public std::logic_error
{
fail() : std::logic_error("fail") {}
using std::logic_error::logic_error;
};
还有一堆呼叫网站,例如:
throw fail();
// or
throw fail("oh dear");
我正在考虑将结构更改为:
struct fail final : public std::logic_error
{
fail() : std::logic_error("fail") { throw * this; }
fail(const char* w) : std::logic_error(w) { throw * this; }
};
此时调用站点可以保持不变,或者被改写为更短的:
fail();
// or
fail("oh dear");
这实质上意味着我不再需要到处写 throw。我还可以使用名称“fail”继续捕获异常。这似乎确实有效,但让我怀疑我以后可能会后悔这个选择。
谢谢
编辑:稍微考虑一下行为。
1/ Throw *this 将生成 *this 的副本,或者如果这对复制省略算公平游戏,则移动它,因此 logic_error 触发的析构函数不是问题
2/ 没有成员的类的默认复制构造函数可能只是基类的复制构造函数,所以可能可以复制 *this
3/ 通过异常返回的 *this 的副本对于任何未在初始化列表中设置的成员可能具有未定义的值
4/ 可以在构造过程中调用成员函数。 (默认)复制构造函数是一个成员函数,因此可以在构造过程中调用。 throw *this 将调用复制构造函数。所以我仍然相信代码是合法的
【问题讨论】:
-
写
throw有什么不好?我不敢相信你经历所有这些只是为了让代码更难阅读。 -
如果您真的想避免一遍又一遍地重复
throw,请考虑将您的错误处理登录包装到包含整个抛出的高阶函数 /try/catch 错误处理流程。要么全部抽象掉,要么一个都不抽象。 -
throw *this的合法性如何?在构造函数中抛出异常会取消构造并自动销毁任何已构造的成员,因此您最终会得到一个死对象。还是throw先复制? -
@JonChesterfield :如果派生类构造函数抛出该类被认为未构造并且调用基类的析构函数来清理混乱。捕手正在捕捉一个被破坏的物体。
-
@JonChesterfield : 构造函数正常返回后,如果构造函数抛出,对象的析构函数将不会被调用,因为它从未被认为是构造的。