0

I am using the approach below for convenience. ie a convenient means of accessing the same myapp instance in a larger program. The code compiles and runs correctly on my machine but want to ask if anyone sees any problems with this approach?

For example, the this ptr is assigned to the_app in the constructor? Is that ok? My concern is that object is still being constructed. but if last line of constructor then ok? Or is it because it is a pointer so doesn't matter because as long as used when fully constructed will be ptr to full object?

#include <iostream>

using namespace std;

class myapp
{
public:
   myapp() : m_data(0)
   {
     the_app = this;
   }

   void DoIt() { cout << "doing it\n"; }

   static myapp* the_app;

private:
   int m_data;
};

myapp* myapp::the_app = 0;

int main(int argc, char* argv[])
{
myapp app;

    app.DoIt();  //doing it using member function

    myapp::the_app->DoIt();  //accessing using static ptr
return 0;
}
Angus Comber
  • 9,316
  • 14
  • 59
  • 107

6 Answers6

1

This is working as expected. BUT there are a couple of issues:

  • When the instance is deleted, the destructor should set the class variable back to zero. You didn't write about that.
  • When another instance is created, the class variable changes and maybe this leads to the first instance getting lost...
  • It does not seem like a good idea (just my personal impression)
HWende
  • 1,705
  • 4
  • 18
  • 30
1

If what you are after is static access to a single instance of a class, then you might want to check out the C++ Singleton design pattern

Community
  • 1
  • 1
grim
  • 143
  • 1
  • 7
0

It's not ok:

{
   myapp app;
}
myapp::the_app->DoIt(); 

This would be illegal, as myapp::the_app is a dangling pointer at this stage.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
0

If you mean to initialize it, then no, you must explicitly define your static member variables and initialize them there:

If the data member is to be explicitly initialized, an initializer must be provided with the definition

There's only one per class, and is shared between all the objects. Static data members are accessed through static function members.

If you didn't mean to initialize, then you need to take into the account that each new instance of your class overwrites the value, and you always have the last pointer created. When your class is destructed - that pointer may become invalid.

littleadv
  • 20,100
  • 2
  • 36
  • 50
0

Problems I can see:

  1. If you subclass myapp, the subclass won't be fully constructed when the pointer is assigned.
  2. The static pointer isn't cleared in the myapp destructor because you haven't written one. The pointer might live on after the object has been destroyed, if your real code doesn't have it on the stack of main().
  3. Multi-threading: If you are using multi-threading then you have a problem, since the assignment may be re-ordered before the rest of the myapp initialisation. Also assigning the pointer might not be atomic depending on the platform.
Douglas Leeder
  • 52,368
  • 9
  • 94
  • 137
0

As others have pointed out, problems are:

  • a new instance could be created at some point, unexpectedly replacing your my_app instance
  • a dangling pointer remains when the instance is destroyed
  • when you derive from my_app, the pointer is assigned before the object is fully constructed.

You could alleviate the first two of these problems by adding

assert(the_app == NULL);

to your constructor and

the_app = NULL;

to your destructor.

Alternative solutions that come to mind:

std::scoped_ptr<my_app> the_global_app;

... if you use a single global object, you might as well admit that you are using a global variable. In your main function:

int main(int argc, char* argv[])
{
    the_global_app.reset( new myapp() ); // or a derived class

    the_global_app->DoIt();  //accessing using static ptr
    return 0;
}

If you don't intend to derive from myapp, you might even be tempted to use a plain global variable:

myapp the_global_app;

int main(int argc, char* argv[])
{
    the_global_app.DoIt();  //accessing using static ptr
    return 0;
}

... but then you need to be aware that other global objects defined in different source files might not have been initialized (std::cout is guaranteed to be available, though).

wolfgang
  • 4,883
  • 22
  • 27