12

I have this existing code where they have a class and an initialization method in that class. It is expected that once the object of the class is created, they need to call initialize on it.

Reason why the initialize method exist The object gets created early to have a global scope and then the initialize method gets called later after loading a dll which it depends on.

Issue with having the initialize The class now has this bool isInitialized which needs to be checked in every method before it proceeds and returns error if it is not initialized. Simply put, it is a big pain.

One possible solution Initialize in the constructor. Have just a pointer to the object in the global scope. Create the actual object after the dll is loaded.

Issue with the above solution Anyone who creates an object of this class needs to know that it needs to be created only after the dll is loaded or else it will fail.

Is this acceptable?

4 Answers4

9

Sounds like a work for a virtual proxy.

You could create a virtual proxy containing a reference to the object in question. While the DLL is no loaded, the Proxy could offer certain default behavior to clients, once the DLL is loaded, the proxy will simply forward all requests to the real subject.

The virtual proxy will be responsible for checking the DLL initialization and based on this decides if the request should be delegated to the real subject.

Proxy Pattern in Wikipedia

How do you like this idea?

edalorzo
  • 2,676
4

Nothing useful occurs if the DLL is not yet loaded; the object only generates an error. Is it a fatal error? How is the error handled?

Does your testing methodology ensure that this error never occurs in the finished product?

It sounds like a job for testing, not for architectural design. Don't just return an error, assert that it never happens.

Fix any clients of the class that presently catch and ignore the error to not try and cause it in the first place.

A multithreaded pattern might be to set a shared condition variable after loading the DLL, and have the object's constructor wait (and block other threads) until the DLL is loaded.

2

First thing: avoid global objects as the pest, unless their state never changes (configuration).

Now, if you're stuck with it, for whatever reasons, there are several designs that could probably help you.

I came up with two ideas:

  1. Use a Facade to load the DLL. The Object may only be accessed through the Facade, the Facade loads the DLL upon creation and instantiate the Object at the same time.

  2. Use a Proxy, but the smart kind ;)

Let me elaborate on the second point, since I fear that @edalorzo's answer might have frighten you:

// 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;
}

Now you only have a single check.

This can also be done through some kind of smart pointer:

Pointer<Object> o;

Here you only reserve space for a pointer, initially null, and only when the DLL is loaded will you actually allocate the object. All previous accesses should raise an exception (NullException :p ?) or terminate the program (cleanly).

Matthieu M.
  • 15,214
1

This is a tricky question. I do feel that architecture may help with the problem.

From the evidence, it sounds like the .dll isn't loaded when the program is loaded. It almost sounds like a plugin.

One thing that comes to mind is that you have to initialize the .dll. The programmer has to assume that the object won't come back reliably, anyways. You might be able to take advantage of this ( bool isObjectLoaded() { return isInitialized; } ) , but you'll definitely get more bug reports over your checks.

I was thinking of a singleton.

If you call the singleton, it should return the correct object if it can retrieve one. If it cannot return the correct object, then you should get some error value / nullptr / empty base object. This wouldn't work if the object can die on you, though.

Also, if you need multiple instances of the object, you can use something like a Factory instead.