旧版代码在析构函数中引发异常

时间:2019-06-07 08:37:01

标签: c++ visual-c++

我正在维护相当旧的旧代码。我的先驱在异常处理方面处于先驱地位(<2000)。处理非标准行为的抛出和捕获逻辑似乎已经奏效。

他们实现了一种不错的抛出方法:

TL_THROW_EXCEPTION(ISQL_MSG_XML_PARSER_ERROR) << msg; 

TL_THROW_EXCEPTION扩展为:

TLThrowTec::CTLThrowExceptionTechnical::ThrowT(__FILE__,__LINE__, 
                                      ISQL_MSG_XML_PARSER_ERROR) << msg;

它将在堆栈上创建一个TLThrowTec :: CTLThrowExceptionTechnical实例,并通过移位操作来设置消息字符串。析构函数创建并引发异常。

stackoverflow中的2008年条目解释了该年的状态: throwing exceptions out of a destructor当时似乎奏效了。

但是现在Visual Studio 17允许抛出,但不再捕获。

由于遗留代码是整个系统的一部分,因此它会生成日志文件条目,例如“未处理的操作系统异常”。

我想在不对源代码进行太多更改的情况下恢复catch逻辑。最好是为TL_THROW_EXCEPTION提供#define。

有没有一种方法可以重新定义宏,以便在消息中引发异常?

如果我搜索TL_THROW_EXCEPTION,这是最后一行:

匹配行:770个匹配文件:217搜索到的文件总数:3159

我不喜欢全部触摸。

4 个答案:

答案 0 :(得分:1)

现代C ++默认将所有析构函数指定为非抛出。并且,如果从指定为非抛出的任何函数引发了异常,则该程序将立即终止。这是因为抛弃析构函数的想法是令人讨厌的。在堆栈展开期间会自动调用析构函数,而已在传输异常。在这种情况下,再次抛出将自身终止程序。并且所有标准容器都会警告UB,如果包含对象的析构函数曾经抛出过。

但是您的用例不容易触发任何这种情况。 ThrowT对象在我看来是要创建为立即抛出某些东西的临时对象,它们不会徘徊在分解其他对象时调用其析构函数。因此,我们可以将它们标记为再次抛出以恢复功能。像这样...

ThrowT::~ThrowT() noexcept(false) {
  // as before
}

...将使宏再次工作。

答案 1 :(得分:0)

  

是否可以重新定义宏?

是的,只需取消定义,然后重新定义,例如:

#undef  TL_THROW_EXCEPTION 

#define TL_THROW_EXCEPTION ...

当然,如果您能想到一种使其成为class或函数的方法,则最好在#undef之后再执行此操作,而不是使用宏。

更像是:

#undef  TL_THROW_EXCEPTION 

class TL_THROW_EXCEPTION 
{ ... }

然后定义构造函数以创建一个可以提供所需行为的实例。

答案 2 :(得分:0)

只需将异常产生类型调整为 be 异常,并使用:

public interface DataProcessor {
  public boolean supports(MyInput input);
  public MyOutput process(MyInput input);
}

@Service
public class YesDataProcessor implements DataProcessor {
  public boolean supports(MyInput input) {
    return input.getSomething().equals("yes");
  }

  public MyOutput process(MyInput input) {
    // ... transforming to output
    return 
  }
}

@Service
public class NoDataProcessor implements DataProcessor {
  public boolean supports(MyInput input) {
    return input.getSomething().equals("no");
  }

  public MyOutput process(MyInput input) {
    // ... transforming to output
    return output;
  }
}


@Service
public class MyDataProcessorRegistry {
  @Autowired
  private List<DataProcessor> processors;

  public Optional<DataProcessor> getProcessor(MyInput input) {
    return processors.stream().filter(p -> p.supports(input)).findFirst();
  }
}

由于#undef TL_THROW_EXCEPTION #define TL_THROW_EXCEPTION(msg_) \ throw YourExceptionType(__FILE__, __LINE__, (msg_)) 的优先级比throw低,因此这将首先计算聚合表达式,然后抛出其结果。

答案 3 :(得分:0)

只需修复该类:

  1. std::uncaught_exceptions()(复数,不是单数)的结果保存在ctor中。
  2. 标记dtor noexcept(false)以启用传播异常。
  3. 仅当调用std::uncaught_exceptions()时才返回dtor返回保存的计数。否则,尝试构建异常会导致异常,然后将自己扔进混乱中将被std::terminate调用。

我希望您的构造函数使用std::stringstream。否则,也可以考虑修复该疏忽。