【问题标题】:How can I replace my c++ exception macro with an inline function with __LINE__ and __FILE__ support?如何用支持 __LINE__ 和 __FILE__ 的内联函数替换我的 c++ 异常宏?
【发布时间】:2015-04-04 23:24:41
【问题描述】:

我目前正在阅读 Scott Meyers 的《Effective 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++ 文件。

有什么办法可以规避这种行为,或者我应该坚持使用旧的宏吗?我在这里阅读了这个帖子,我已经怀疑我的第二个示例可能无法正常工作:

【问题讨论】:

  • 第二个不是宏,所以介绍不准确。有时宏做事的方式(像这样)。
  • @WhozCraig 谢谢你的提示,我改了。

标签: c++ exception macros c-preprocessor inline


【解决方案1】:

不要使用__(双下划线),因为它是保留的。拥有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());
}

【讨论】:

    【解决方案2】:

    我看到这是一个老问题,但我认为在异常宏中打印行的方法存在根本缺陷,我认为我有更好的选择。我假设宏的使用类似于下面的代码:

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

    【讨论】:

      【解决方案3】:

      请考虑在您的情况下使用类似函数的#defineinline 函数相比还有另一个区别。您可以在宏的调用中使用流式操作符和参数组成您的消息文本:

      __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 在 Microsoft::VisualStudio::CppUnitTestFramework 命名空间 (VC\UnitTest\Include\CppUnitTestAssert.h) 中使用他们的 __LineInfo 类。见https://msdn.microsoft.com/en-us/library/hh694604.aspx

      【讨论】:

        【解决方案4】:

        使用std::experimental::source_location,您可以这样做:

        #include <experimental/source_location>
        
        void THROW_EX(const std::string_view& message,
                      const std::experimental::source_location& location
                          = std::experimental::source_location::current())
        {
            std::ostringstream stream;
            stream << "EXCEPTION: " << message
                   << ", file " << location.file_name()
                   << " line " << location.line();
            throw ExceptionImpl(stream.str());
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-12
          • 1970-01-01
          • 2016-02-16
          • 2013-01-15
          相关资源
          最近更新 更多