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