我正在尝试开发一个Exception类,该类允许收集相关的数据流样式。

Custom stream to method in C++?之后,我扩展了自己的类(class):

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());
}

但是编译器会产生一个错误:
HTTPClient.cpp:246:113: error: use of deleted function 'std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)'

(这就是throw的行。)

我意识到流没有复制构造函数,但是我认为捕获一个引用而不是对象就足够了。我该如何克服-我可以扔一个“吞下”流的物体吗?

最佳答案

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

#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;
        }
}

上面的解决方案并不完美。如果str = innerStream.str()抛出,那么std::terminate将被调用。如果要使what方法完全成为noexcept,则有两种选择:
  • 将流的内容复制到复制构造函数中的str变量中。这样一来,您将无法在调用前调用what方法获取异常消息。
  • 将流的内容复制到复制构造函数和str运算符内部的<<变量中。在这种情况下,您将能够在抛出之前获取异常消息,但是每次调用运算符(operator)时您都将复制消息,这可能是一个过大的杀伤力。
  • 关于c++ - 我可以丢流吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37191227/

    10-11 22:59
    查看更多