我现在读了Scott的“有效C++”一书。它说,对于类似函数的宏,我更喜欢inline
函数而不是#define
函数。
现在,我尝试编写一个内联函数来替换异常宏。我以前的宏如下所示:
#define __EXCEPTION(aMessage) \
{ \
std::ostringstream stream; \
stream << "EXCEPTION: " << aMessage << ", file " <<__FILE__ << " line " << __LINE__; \
throw ExceptionImpl(stream.str()); \
}
我的新内联功能如下:
inline void __EXCEPTION(const std::string aMessage)
{
std::ostringstream stream;
stream << "EXCEPTION: " << aMessage << ", file " <<__FILE__ << " line " << __LINE__;
throw ExceptionImpl(stream.str());
}
正如一些人已经预料到的,现在__FILE__
和__LINE__
宏是无用的,因为它们总是引用带有内联函数定义的C++文件。
有什么办法可以避免这种行为吗?还是我应该坚持我以前的宏观政策?我在这里阅读了这些线程,并且我已经怀疑我的第二个示例可能无法正常工作:
发布于 2015-02-05 07:42:04
不要使用__
(双下划线),因为它是保留的。拥有一个inline
函数更好。
但是,这里需要宏和函数的混合,因此可以执行以下操作:
#define MY_EXCEPTION(aMessage) MyException(aMessage, __FILE__, __LINE__)
inline void MyException(const std::string aMessage,
const char* fileName,
const std::size_t lineNumber)
{
std::ostringstream stream;
stream << "EXCEPTION: " << aMessage << ", file " << fileName << " line " << lineNumber;
throw ExceptionImpl(stream.str());
}
发布于 2016-05-17 16:14:00
我认为这是一个老问题,但我认为在异常宏中打印行的方法是有根本缺陷的,我认为我有更好的选择。我假定宏的使用类似于以下代码:
try {
/// code
throw;
}
catch (...) { __EXCEPTION(aMessage); }
使用这种方法,宏会打印异常catch'ed
**.为的位置,但对于故障排除和调试,所在的位置** throw'n
通常更有用。
要获取该信息,我们可以将__FILE__
和__LINE__
宏附加到异常。然而,我们仍然不能完全摆脱宏,但是我们至少可以得到正确的抛出位置:
#include <iostream>
#include <exception>
#include <string>
#define MY_THROW(msg) throw my_error(__FILE__, __LINE__, msg)
struct my_error : std::exception
{
my_error(const std::string & f, int l, const std::string & m)
: file(f)
, line(l)
, message(m)
{}
std::string file;
int line;
std::string message;
char const * what() const throw() { return message.c_str(); }
};
void my_exceptionhandler()
{
try {
throw; // re-throw the exception and capture the correct type
}
catch (my_error & e)
{
std::cout << "Exception: " << e.what() << " in line: " << e.line << std::endl;
}
}
int main()
{
try {
MY_THROW("error1");
} catch(...) { my_exceptionhandler(); }
}
如果我们愿意使用boost::exception
,还有一个额外的改进:我们可以去除宏定义,至少在我们自己的代码中是这样。整个程序变得更短,代码执行和错误处理的位置可以很好地分开:
#include <iostream>
#include <boost/exception/all.hpp>
typedef boost::error_info<struct tag_error_msg, std::string> error_message;
struct error : virtual std::exception, virtual boost::exception { };
struct my_error: virtual error { };
void my_exceptionhandler()
{
using boost::get_error_info;
try {
throw;
}
catch(boost::exception & e)
{
char const * const * file = get_error_info<boost::throw_file>(e);
int const * line = get_error_info<boost::throw_line>(e);
char const * const * throw_func = get_error_info<boost::throw_function>(e);
std::cout << diagnostic_information(e, false)
<< " in File: " << *file << "(" << *line << ")"
" in Function: " << *throw_func;
}
}
int main()
{
try {
BOOST_THROW_EXCEPTION(my_error() << error_message("Test error"));
} catch(...) { my_exceptionhandler(); }
}
发布于 2015-05-11 11:47:24
请考虑在您的情况下使用类似#define
函数的宏与inline
函数相比还有另一个不同之处。您可以在宏调用中使用流运算符和参数作为消息的文本组成:
__EXCEPTION( "My message with a value " << val )
但大多数时候,我都需要这样的东西,就是检查某个特定的条件(比如断言)。因此,您可以扩展@iammilind的示例,如下所示:
#define MY_EXCEPTION_COND( cond ) \
if (bool(cond) == false) \
{ \
std::string _s( #cond " == false" ); \
MyException(_s, __FILE__, __LINE__); \
}
或者一些更专业的东西,其中的值也是打印出来的:
template <typename T>
inline void MyExceptionValueCompare(const T& a,
const T& b,
const char* fileName,
const std::size_t lineNumber)
{
if (a != b)
{
std::ostringstream stream;
stream << "EXCEPTION: " << a << " != " << b << ", file " << fileName << " line " << lineNumber;
throw ExceptionImpl(stream.str());
}
}
#define MY_EXCEPTION_COMP( a, b ) MyExceptionValueCompare(a, b, __FILE__, __LINE__)
另一种可能需要查看的方法是微软在Microsoft::VisualStudio::CppUnitTestFramework
命名空间中使用他们的Microsoft::VisualStudio::CppUnitTestFramework
类(VC\UnitTest\Include\CppUnitTestAssert.h)。请参阅https://msdn.microsoft.com/en-us/library/hh694604.aspx
https://stackoverflow.com/questions/28338328
复制相似问题