【发布时间】:2021-06-30 18:56:55
【问题描述】:
在我们项目的核心中,我们有以下代码:
template<typename T>
T& get_factory_instance(bool reset = false)
{
static boost::scoped_ptr<T> factory_instance;
if (reset)
{
factory_instance.reset();
return *(T*)0;
}
if (!factory_instance)
{
factory_instance.reset(new T());
}
return *factory_instance;
}
如果reset 是true,则根据标准它是UB。
这个带有参数true的函数只有在返回值被忽略时才会被调用,因此不会访问内存。这是强制性的,当我们将此函数的调用添加到签名为void() 的函数的单例列表中时,不能从服务调用函数,只能从库调用函数。如果连接丢失,我们需要这种奇怪的 hack 来清除连接到数据库的准备好的语句。
所以,基本上问题是:如果我们不访问此内存,它会触发吗?如果是的话,如果有可能的话,我们怎么可能在不重写所有依赖于这个函数的代码的情况下修复它?
当T 构造函数被调用时,它会构造预处理语句并打开/使用与数据库的连接,因此,创建虚拟对象并不是一个好主意。
在 out 库中,我们有近 80 次使用参数 true 调用此函数。它于 2015 年推出。在大多数情况下使用此函数而不带参数的代码如下所示:
fields_t& fields = get_factory_instance<fields_t>();
提前致谢。
【问题讨论】:
-
您可以返回对虚拟
static实例的引用。您将返回对标记值的非常量引用,这不是很好,但至少不会是 UB。 -
reset标志的用途是什么?不应该导致工厂实例被重新创建?该标志应该首先解决什么问题? -
@ForEveR 在我看来
get_factory_instance是一个根本性的破坏设计,您的团队应该咬紧牙关,正确地修复它(重构它)。 80 个呼叫站点很重要,但也不是压倒性的。 -
@Martin.Martinsson> 这完全是题外话,但我发现它之前的 OMG 和这里的 LOL 很烦人。我们都必须处理多年前某天离开公司的人编写的遗留代码。如果没有人对一个严肃的问题发笑,这已经很烦人了。请:)
-
@Martin.Martinsson,那么,如果你不更多地使用这个内存,会有什么问题呢?伙计,这显然是题外话。我知道,这是导致 UB 的错误代码,但已经完成了。这不是我的代码通过,所以,你的话是错误的。
标签: c++ reference undefined-behavior