【问题标题】:Is it ok to assign this to a static pointer in constructor as in example here可以将它分配给构造函数中的静态指针,如示例here
【发布时间】:2012-04-04 08:41:29
【问题描述】:

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

比如this ptr是在构造函数中赋值给the_app的?那样可以么?我担心的是对象仍在构建中。但是如果构造函数的最后一行那么好吗?还是因为它是一个指针所以没关系,因为只要在完全构造时使用就会指向完整对象?

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

【问题讨论】:

  • 实例化另一个 myapp 会发生什么?
  • 语言注释:我通常将“a = b”读作“b 分配给 a”而不是“a 分配给 b”。

标签: c++ static constructor


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 是的,我认为这可能是最好的方式
    【解决方案3】:

    不行:

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

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

    【讨论】:

      【解决方案4】:

      我能看到的问题:

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

      【讨论】:

        【解决方案5】:

        如果你的意思是初始化它,那么不行,你必须显式定义你的静态成员变量和initialize them there:

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

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

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

        【讨论】:

        • 他确实这样做了 - myapp* myapp::the_app = 0;
        • “不,你必须明确定义你的静态成员变量并初始化它们”他正在这样做。
        • @LuchianGrigore 现在好点了吗?我确信人们会读完第一句话,但这个假设始终不适合你:-/
        • 当我阅读答案时,它只有第一部分。不要个人认为。
        【解决方案6】:

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

        • 可能会在某个时候创建​​一个新实例,意外替换您的 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 保证可用)。

        【讨论】:

          猜你喜欢
          • 2018-10-03
          • 1970-01-01
          • 1970-01-01
          • 2018-04-15
          • 1970-01-01
          • 1970-01-01
          • 2022-01-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多