0

便宜上、以下のアプローチを使用しています。つまり、より大きなプログラムで同じ myapp インスタンスにアクセスする便利な手段です。コードは私のマシンで正しくコンパイルおよび実行されますが、このアプローチに問題があるかどうかを尋ねたいですか?

たとえば、 this 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;
}
4

6 に答える 6

1

クラスの単一インスタンスへの静的アクセスを求めている場合は、 C++ Singleton 設計パターンを確認することをお勧めします。

于 2012-04-04T09:01:34.783 に答える
1

これは期待どおりに機能しています。ただし、いくつかの問題があります。

  • インスタンスが削除されると、デストラクタはクラス変数をゼロに戻す必要があります。あなたはそれについて書いていません。
  • 別のインスタンスが作成されると、クラス変数が変更され、最初のインスタンスが失われる可能性があります...
  • あまりいいアイデアとは思えません(あくまで個人の感想です)
于 2012-04-04T08:50:18.993 に答える
0

他の人が指摘しているように、問題は次のとおりです。

  • ある時点で新しいインスタンスが作成され、my_appインスタンスが予期せず置き換えられる可能性があります
  • インスタンスが破棄されても、ダングリングポインタが残ります
  • my_appから派生する場合、オブジェクトが完全に構築される前にポインターが割り当てられます。

これらの問題の最初の2つを追加することで、軽減できます。

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ただし、使用可能であることが保証されています)。

于 2012-04-04T09:11:47.710 に答える
0

それは大丈夫ではありません:

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

myapp::the_appこの段階ではダングリング ポインターと同様に、これは違法です。

于 2012-04-04T08:47:05.550 に答える
0

初期化するつもりなら、いいえ、静的メンバー変数を明示的に定義し、そこで初期化する必要があります。

データ メンバーを明示的に初期化する場合は、初期化子を定義と共に提供する必要があります。

クラスごとに 1 つだけあり、すべてのオブジェクト間で共有されます。静的データ メンバーには、静的関数メンバーを介してアクセスします。

初期化するつもりがなかった場合は、クラスの新しいインスタンスごとに値が上書きされ、常に最後のポインターが作成されることを考慮する必要があります。クラスが破棄されると、そのポインターが無効になる場合があります。

于 2012-04-04T08:47:19.607 に答える
0

私が見ることができる問題:

  1. myapp をサブクラス化すると、ポインターが割り当てられたときにサブクラスが完全に構築されません。
  2. 静的ポインターは、作成していないため、デストラクターでクリアされmyappません。実際のコードのスタックにポインターがない場合、ポインターはオブジェクトが破棄された後も存続する可能性がありますmain()
  3. マルチスレッド: マルチスレッドを使用している場合、残りのmyapp初期化の前に割り当ての順序が変更される可能性があるため、問題が発生します。また、プラットフォームによっては、ポインターの割り当てがアトミックではない場合があります。
于 2012-04-04T08:47:38.123 に答える