C++ 我能扔一条小溪吗?

C++ 我能扔一条小溪吗?,c++,exception,iostream,ostream,C++,Exception,Iostream,Ostream,我正在尝试开发一个异常类,它允许收集相关的数据流样式 接下来,我扩展了自己的课程: class NetworkException : public std::exception, public std::ostream 从流中提取错误数据,然后返回通过.what()获取的任何数据 然后我试着这样做: try { ssize_t ret = send(sock, headBuffer, headLength, MSG_MORE); if (ret <= 0) throw

我正在尝试开发一个异常类,它允许收集相关的数据流样式

接下来,我扩展了自己的课程:

class NetworkException : public std::exception, public std::ostream
从流中提取错误数据,然后返回通过
.what()
获取的任何数据

然后我试着这样做:

try {
    ssize_t ret = send(sock, headBuffer, headLength, MSG_MORE);

    if (ret <= 0)  throw NetworkException() << "Error sending the header: " << strerror(errno);

    // much more communication code

} catch (NetworkException& e) {
    connectionOK = false;
    logger.Warn("Communication failed: %s",e.what());
}
struct NetworkException : std::exception
{
    using std::exception::exception;

    template <class T>
    NetworkException& operator<<(const T& arg) {
        std::ostringstream oss; 
        oss << arg;
        err.append(oss.str());
        return *this;
    }

    const char* what() const noexcept override {
        return err.c_str();
    }

private:
    std::string err;
};
试试看{
ssize_t ret=发送(sock、headBuffer、headLength、MSG_MORE);

if(ret异常总是至少复制一次。通过引用捕获异常可避免第二次复制

只是一个想法:也许你可以将你的流嵌入一个智能指针,比如
std::shared\u ptr
,然后抛出那个智能指针


就我个人而言,我通常在任何地方都使用
std::runtime\u error

除了ZunTzu的答案:使用ostringstream

::std::ostringstream what;
what << "Error sending the header: " << strerror(errno);
throw ::std::exception(what.str());
::std::ostringstream what;

你想做的事以前已经被很多人尝试过了。当然这是可能的,但需要一些技巧(类似于制作流式记录器所需的技巧)

这也是一个坏主意,因为:

  • 它将流的概念与异常的概念结合起来

  • 使用单个模板函数可以更简单地完成此操作

  • 事实上,这里有3个非常简单的选择:

    #include <iostream>
    #include <sstream>
    #include <exception>
    #include <stdexcept>
    #include <boost/format.hpp>
    
    template<class...Args>
    std::string collect(Args&&...args)
    {
        std::ostringstream ss;
        using expand = int[];
        void(expand{0, ((ss << args), 0)...});
        return ss.str();
    }
    
    struct collector : std::ostringstream
    {
        operator std::string() const {
            return str();
        }
    };
    
    // derive from std::runtime_error because a network exception will always
    // be a runtime problem, not a logic problem
    struct NetworkException : std::runtime_error
    {
        using std::runtime_error::runtime_error;
    };
    
    int main()
    {
        try {
            throw NetworkException(collect("the", " cat", " sat on ", 3, " mats"));
    
        } catch (const std::exception& e) {
            std::cout << e.what() << std::endl;
        }
    
        try {
            throw NetworkException(collector() << "the cat sat on " << 3 << " mats");
    
        } catch (const std::exception& e) {
            std::cout << e.what() << std::endl;
        }
    
        try {
            throw NetworkException((boost::format("the cat sat on %1% mats") % 3).str());
    
        } catch (const std::exception& e) {
            std::cout << e.what() << std::endl;
        }
    
    
        return 0;
    }
    
    最后,可能是最类似流的解决方案:

    template<class Exception>
    struct raise
    {
        [[noreturn]]
        void now() const {
            throw Exception(_ss.str());
        }
    
        std::ostream& stream() const { return _ss; }
    
        mutable std::ostringstream _ss;
    };
    
    template<class Exception, class T>
    const raise<Exception>& operator<<(const raise<Exception>& r, const T& t)
    {
        using namespace std;
        r.stream() << t;
        return r;
    }
    
    struct now_type {};
    static constexpr now_type now {};
    
    template<class Exception>
    void operator<<(const raise<Exception>& r, now_type)
    {
        r.now();
    }
    
    模板
    结构提升
    {
    [[noreturn]]
    void now()常量{
    抛出异常(_ss.str());
    }
    std::ostream&stream()常量{return}
    可变std::ostringstream _ss;
    };
    模板
    常量提升和操作员
    我能扔一条小溪吗

    不可以。抛出异常时,将从异常表达式构造临时对象。由于流对象不能从另一个流对象构造,因此不能抛出流对象

    从C++11标准:

    15.1引发异常

    3 throw表达式初始化临时对象,称为异常对象,其类型是通过从
    throw
    的操作数的静态类型中删除任何顶级cv限定符,并将类型从“T数组”或“函数返回T”调整为“指向T的指针”或“指向返回T的函数的指针”来确定的临时变量是一个左值,用于初始化匹配处理程序(15.3)中命名的变量


    不能使用默认复制构造函数复制包含流对象的对象,但可以编写自己的复制构造函数来复制流的内容

    #include <iostream>
    #include <sstream>
    
    struct StreamableError : public std::exception {
            template <typename T>
            StreamableError& operator << (T rhs) {
                innerStream << rhs;
                return *this;
            }
    
            StreamableError() = default;
    
            StreamableError(StreamableError& rhs) {
                    innerStream << rhs.innerStream.str();
            }
    
            virtual const char* what() const noexcept {
                str = innerStream.str();  //this can throw
                return str.c_str();
            }
    
        private:
            std::stringstream innerStream;
            mutable std::string str;
    };
    
    
    int main() {
            try {
                    throw StreamableError() << "Formatted " << 1 << " exception.";
            } catch (std::exception& e) {
                    std::cout << e.what() << std::endl;
            }
    }
    
    #包括
    #包括
    struct StreamableError:公共标准::异常{
    模板
    
    StreamableError&operator更简单的方法是不存储
    std::ostringstream
    ,如下所示:

    try {
        ssize_t ret = send(sock, headBuffer, headLength, MSG_MORE);
    
        if (ret <= 0)  throw NetworkException() << "Error sending the header: " << strerror(errno);
    
        // much more communication code
    
    } catch (NetworkException& e) {
        connectionOK = false;
        logger.Warn("Communication failed: %s",e.what());
    }
    
    struct NetworkException : std::exception
    {
        using std::exception::exception;
    
        template <class T>
        NetworkException& operator<<(const T& arg) {
            std::ostringstream oss; 
            oss << arg;
            err.append(oss.str());
            return *this;
        }
    
        const char* what() const noexcept override {
            return err.c_str();
        }
    
    private:
        std::string err;
    };
    
    struct NetworkException:std::exception
    {
    使用std::exception::exception;
    模板
    
    NetworkException&operator@MohamadElghawi的可能副本:那么这就变成了“我能为流对象创建一个复制构造函数吗?”我个人避免使用<代码> <代码>异常,如:代码> STD::RunTimeOrthyEng/EXECUT>因为.joTik真。例外在C++中被破坏了。我认真考虑在收藏夹类< /Cuff>方法上作弊:重载异常<代码>operator@SF.请参阅结尾处的第四个选项。@SF。再想一想,这就是不安全。将删除它。@SF.为选项4添加了更安全的替换。如果一个愚蠢的短字符串的纯拷贝抛出,那么一般情况是灾难性的,异常成功完成不会有任何帮助。在这种情况下,程序无法正常恢复操作,或者这种情况的原因是错误的在那个异常附近,它在一个尸体上涂口红——如果我不能依赖于复制50个字符的能力,系统可以做的最好就是让看门狗踢它。在调试器下它不会有问题。没有调试器,它就无法恢复了。这是相当干净的,但是主要的问题是,实现将复制
    err
    多次,每个操作数到
    
    
    struct NetworkException : std::exception
    {
        using std::exception::exception;
    
        template <class T>
        NetworkException& operator<<(const T& arg) {
            std::ostringstream oss; 
            oss << arg;
            err.append(oss.str());
            return *this;
        }
    
        const char* what() const noexcept override {
            return err.c_str();
        }
    
    private:
        std::string err;
    };