c++ - 无条件地从构造函数中抛出 *this

标签 c++ exception

我相信从构造函数体内抛出 *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 将调用复制构造函数。所以我还是相信代码是合法的

最佳答案

我对您编写富有表现力的代码的愿望表示同情。

这是我想出的用于我们的代码库的东西,特别是在调用以类似 bool 整数的形式返回成功或失败的 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");
}

异常(exception)情况更有趣:

#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

关于c++ - 无条件地从构造函数中抛出 *this,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41664138/

相关文章:

C++ 运算符重载未按预期工作

c++ - 将 <windows.h> 的函数与其他类混合使用是一种不好的做法吗?

javascript - 为什么我的 if 条件不能阻止我的脚本崩溃?

c# - 在 ArrayAdapter 构造函数上抛出 Android NoSuchMethodError

c++ - 异常(exception):设备为nullptr。 D3D11中的读取访问冲突

c++ - 如何获得给定进程的窗口站?

c++ - 我是否必须明确地销毁对象才能

c++ - sqrt(x) 和 pow(x,0.5) 的区别

wpf - 有没有一种方法可以在客户端的一个地方处理 WCF 服务器故障?

ruby-on-rails - 如何修复 Ruby "no such file to load -- xsd/qname"错误?