避免使用初始化方法


12

我有这个现有的代码,其中他们有一个类和该类中的初始化方法。预期一旦创建了类的对象,他们就需要在其上调用initialize。

初始化方法存在原因该对象要尽早创建以具有全局作用域,然后在加载依赖的dll之后再调用初始化方法。

具有初始化 的问题该类现在具有此bool isInitialized,需要在每个方法中进行检查,然后再继续进行,如果未初始化则返回错误。简而言之,这是一个很大的痛苦。

一种可能的解决方案 在构造函数中初始化。仅在全局范围内有一个指向该对象的指针。加载dll后创建实际对象。

上述解决方案的问题 任何创建此类的对象的人都必须知道,仅在dll被加载后才需要创建该对象,否则它将失败。

这可以接受吗?


我创建OpenGL的相关对象时OpenGL上下文存在之前需要被实例化有同样的问题,但都应该保持像calllists,纹理等OpenGL的依赖对象

3
愚蠢的问题#1:为什么对象构造函数无法加载DLL(如果尚未加载)?
John R. Strohm

1
表示歉意复活一个老问题,但如果有人在读这在2017年,call_once在C ++ 11。尚未使用C ++ 11的项目应该研究如何在C ++ 11中实现call_once(着重于解决什么问题,然后解决),然后以(陈旧的)C ++风格重新实现它。它需要一个多线程安全同步原语,该原语的状态需要静态初始化(使用恒定值)。请注意,C ++ 11之前的编译器可能还有其他需要满足的特性。
rwong

Answers:


7

听起来像是虚拟代理的工作。

您可以创建一个虚拟代理,其中包含对该对象的引用。当未加载DLL时,代理可以向客户端提供某些默认行为,一旦DLL被加载,代理将简单地将所有请求转发给真实主题。

虚拟代理将负责检查DLL的初始化,并根据此决定是否应将请求委派给真实的主题。

维基百科中的代理模式

您如何看待这个想法?


你真的不能在这里解决很多。对于实际对象中添加的每个方法,您还需要将该方法添加到代理中。没有?

这样避免了记住调用init的问题。函数,但似乎代理中的每个函数仍需要检查以查看是否已加载.dll。

1
@Sriram现在有很大的不同,使用代理,您已将与DLL检查相关的维护限制为一个类:代理。该类的客户端甚至根本不需要了解DLL检查。由于大多数方法都可以进行委派,因此我不必在代理中的两个实际主题中都实现接口就不会有太大的问题。换句话说,在确定DLL已加载之前,您可以阻止创建真实主题,然后您无需每次都检查DLL状态。

@edalorzo:虽然这个主意很好,但是这里的问题是我们已经在谈论代理,而OP则抱怨必须检查其代理的每种方法……
Matthieu M.

4

如果尚未加载DLL,则不会有任何有用的事情发生。该对象只会产生一个错误。这是致命错误吗?错误如何处理?

您的测试方法是否可以确保在成品中永远不会发生此错误?

这听起来像是测试工作,而不是建筑设计工作。不要仅仅返回错误,assert它永远不会发生。

修复当前捕获并忽略该错误的该类的所有客户端,使其一开始就不会尝试导致该错误。

多线程模式可能是在加载DLL之后设置共享条件变量,并让对象的构造函数等待(并阻止其他线程)直到DLL被加载。


我认为您是对的,如果DLL没有正确初始化,则在创建有问题的对象时引发异常没有错。然后,客户端代码将只需要处理该异常,并且测试应确保适当地处理了异常。

2

第一件事:避免将全局对象作为有害生物,除非它们的状态永不改变(配置)。

现在,如果您坚持使用它,无论出于何种原因,有几种设计可能会为您提供帮助。

我提出了两个想法:

  1. 使用外观来加载DLL。只能通过外观访问对象,外观在创建时加载DLL并同时实例化对象。

  2. 使用代理,但很聪明;)

让我详细说明第二点,因为我担心@edalorzo的答案可能会吓到您:

// Private
static Object& GetObjectImpl() { static Object O; return O; }

// Public
static Object& GetObject() {
  Object& o = GetObjectImpl();
  assert(o.isInitialized() && "Object not initialized yet!");
  return o;
}

现在,您只有一张支票。

这也可以通过某种智能指针来完成:

Pointer<Object> o;

在这里,您只为指针保留空间,最初为null,并且只有在加载DLL时,您才实际分配该对象。以前的所有访问都应引发异常(NullException:p?)或终止程序(干净地)。


1

这是一个棘手的问题。我确实认为体系结构可以解决该问题。

从证据来看,听起来好像在加载程序时未加载.dll。听起来几乎像一个插件。

我想到的一件事是,您必须初始化.dll。程序员必须假定该对象无论如何不会可靠地返回。您也许可以利用此(bool isObjectLoaded() { return isInitialized; })优势,但是您肯定会通过检查获得更多的错误报告。

我在想一个单身人士。

如果调用单例,则它可以返回正确的对象(如果它可以检索到一个对象)。如果它不能返回正确的对象,那么您应该获得一些错误值/ nullptr /空的基础对象。但是,如果对象可以在您身上死亡,则此方法将无效。

另外,如果需要该对象的多个实例,则可以使用类似Factory的名称。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.