我认为从构造函数体内抛出*这是合法的。我想知道我是否完全错了(在构造函数完成之前传递一个对象的问题?)或者这在风格上是否令人厌恶。
我发布了第二个更具体的问题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");
这实际上意味着我不再需要在整个地方写点。我还可以使用名称“fail”继续捕获异常。它当然似乎有效,但让我怀疑我可能会后悔这个选择。
谢谢
编辑:稍微考虑一下这种行为。
1 / Throw *这将要么复制* this或移动它,如果这算作复制省略的公平游戏,那么logic_error解雇的析构函数不是问题
2 /没有成员的类的默认复制构造函数可能只是基类的复制构造函数,因此可以复制* this
3 /通过异常返回的* this的副本可能具有未在初始化列表中设置的任何成员的未定义值
4 /构建期间可以调用成员函数。 (默认)复制构造函数是一个成员函数,因此可以在构造期间调用。 throw *这将调用复制构造函数。所以我仍然相信代码是合法的
答案 0 :(得分:2)
我看到的两个缺点:
不是惯用语,因此会让用户感到惊讶的是throw
。所以IMO,它的可读性较差。
您不能从您的类继承(因为该基类抛出)(您可以标记类final
(来自C ++ 11)以突出显示它。)
答案 1 :(得分:2)
我同情你写出富有表现力的代码的愿望。
这是我在代码库中使用的那种东西,特别是在调用返回成功或失败的C API时,它们是一个类似布尔的整数。
#include <stdexcept>
#include <exception>
struct failure : std::runtime_error
{
using runtime_error::runtime_error;
};
template<class Message>
[[noreturn]]
bool fail(Message&& msg)
{
throw failure(std::forward<Message>(msg));
}
int main()
{
extern bool didSomething();
didSomething() or fail("couldn't do it");
}
除了例外之外更有趣:
#include <stdexcept>
#include <exception>
#include <cstdio>
#include <memory>
#include <system_error>
#include <sstream>
#include <iostream>
#include <iomanip>
namespace native
{
struct no_message {};
constexpr no_message join() { return {}; }
template<class First, class...Rest>
std::string join(First&& first, Rest&&...rest)
{
std::ostringstream ss;
ss << first;
using expand = int[];
void(expand{ 0,
((ss << ' ' << rest),0)...
});
return ss.str();
}
[[noreturn]]
void throwSystemError(no_message, int code)
{
throw std::system_error(code, std::system_category());
}
template<class Message>
[[noreturn]]
void throwSystemError(Message&& message, int code)
{
throw std::system_error(code, std::system_category(), message);
}
template<class...Parts>
[[noreturn]]
bool systemError(Parts&&...parts)
{
auto err = errno;
throwSystemError(join(std::forward<Parts>(parts)...), err);
}
struct file_closer {
void operator()(FILE* fp) const noexcept {
std::fclose(fp);
}
};
using FilePtr = std::unique_ptr<FILE, file_closer>;
bool valid(FilePtr const& p) { return p.get(); }
FilePtr openFile(const char* path, const char* mode)
{
auto ptr = FilePtr(std::fopen(path, mode));
valid(ptr) or systemError("opening file", std::quoted(path), "in mode", std::quoted(mode));
return ptr;
}
}
int main()
try
{
auto fptr = native::openFile("ibetthisdoesntexist.txt", "rb");
}
catch(std::system_error const& syserr)
{
std::cerr << "system error: "
<< syserr.what()
<< ", error code " << syserr.code().value()
<< std::endl;
std::exit(100);
}
示例输出:
system error: opening file "ibetthisdoesntexist.txt" in mode "rb": No such file or directory, error code 2