可以将它分配给构造函数中的静态指针,如下例所示

时间:2012-04-04 08:41:29

标签: c++ static constructor

为方便起见,我使用以下方法。即在较大程序中访问同一myapp实例的便捷方法。代码在我的机器上编译并正确运行,但是想问一下是否有人发现这种方法存在任何问题?

例如,将此ptr分配给构造函数中的the_app?这可以吗?我担心的是物体仍在建造中。但是如果最后一行构造函数那么好吗?或者是因为它是一个指针所以无关紧要,因为只要在完全构造时使用ptr到完整对象?

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

6 个答案:

答案 0 :(得分:1)

这是按预期工作的。 但有几个问题:

  • 删除实例时,析构函数应将类变量设置为零。你没有写过这个。
  • 当创建另一个实例时,类变量会发生变化,这可能会导致第一个实例丢失...
  • 这似乎不是一个好主意(只是我的个人印象)

答案 1 :(得分:1)

如果你所追求的是静态访问类的单个实例,那么 你可能想看看 C++ Singleton design pattern

答案 2 :(得分:0)

不行:

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

这是非法的,因为myapp::the_app在这个阶段是一个悬空指针。

答案 3 :(得分:0)

如果您要初始化它,那么不,您必须明确定义静态成员变量和initialize them there

  

如果要显式初始化数据成员,则使用初始化程序   必须提供定义

每个类只有一个,并在所有对象之间共享。静态数据成员可以通过静态函数成员访问。

如果您不打算初始化,那么您需要考虑到您的类的每个新实例都会覆盖该值的帐户,并且您始终会创建最后一个指针。当你的类被破坏时 - 指针可能变得无效。

答案 4 :(得分:0)

我可以看到的问题:

  1. 如果你是myapp的子类,那么当分配指针时,子类将不会被完全构造。
  2. 静态指针未在myapp析构函数中清除,因为您还没有写入。{li>如果您的真实代码没有在main()的堆栈上,指针可能会在对象被销毁后继续存在。
  3. 多线程:如果您使用的是多线程,那么您就会遇到问题,因为可能会在myapp初始化的其余部分之前重新排序。根据平台的不同,分配指针可能不是原子的。

答案 5 :(得分:0)

正如其他人所指出的,问题是:

  • 可以在某个时刻创建一个新实例,意外地替换你的my_app实例
  • 当实例被销毁时,悬空指针仍然存在
  • 从my_app派生时,指针在对象完全构造之前分配。

您可以通过添加

来缓解前两个问题
assert(the_app == NULL);

到你的构造函数和

the_app = NULL;

到您的析构函数。

浮现在脑海中的其他解决方案:

std::scoped_ptr<my_app> the_global_app;

...如果您使用单个全局对象,您可能会承认您正在使用全局变量。在main函数中:

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

如果您不打算从myapp派生,您甚至可能想要使用普通的全局变量:

myapp the_global_app;

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

...但是你需要知道在不同的源文件中定义的其他全局对象可能尚未初始化(尽管保证std::cout可用)。