web-dev-qa-db-ja.com

すべてのヘッダー/ソースファイルからグローバル変数に適切にアクセスするために、グローバル変数を宣言および定義する方法

ええと、私はlearning C++であり、OO以外のことを行う方法を実際に学んだことはありません。 Cスタイルでのコーディングの経験をもう少し増やしたいと思っています。

GobalInformation.h

#pragma once

#ifndef GLOBALINFORMATION_H
#define GLOBALINFORMATION_H

#include "MapInformation.h"

namespace gi {
    MapInformation mapInf;
};

#endif

プロジェクトのすべてのヘッダーとcppからgi :: mapInfにアクセスできるようにしたいと思います。現在、すべてのヘッダーにglobalinformation.hを含めているため、複数の定義でリンカーエラーが発生します。

どうすれば問題を回避できますか?

17
xcrypt

ヘッダーファイルでのみ行う

namespace gi {
    extern MapInformation mapInf;
};

CPPファイルで実際の定義を提供します。

namespace gi {
    MapInformation mapInf;
};

意図したとおりに動作します。

ダイナミックリンクライブラリの境界を越えてMapInformationを使用している場合は、定義cppファイルを含むライブラリに対してリンクする必要がある場合があります。また、Windowではdllimport/dllexportを使用する必要があるかもしれません

31

複数のコンパイルユニットにグローバルがあると、初期化の順序の問題が発生しやすいことに注意してください。各グローバルを、参照を返す関数に置き換えることを検討することをお勧めします。あなたの場合、これを1つのcppファイルに入れ、ヘッダーで宣言します。

namespace gi {
    MapInformation& getMapInf()
    {
        static MapInformation result;
        return result;
    }
}
13
Kevin Hopps

グローバル変数はCですが、名前空間はC++です。グローバル変数の使用と、それらをシングルトンパターンに置き換える方法については良い議論があります: グローバルとシングルトン

そして、ここに簡単なサンプルがあります: CPP/Classes/Singleton

3
SChepurin

おそらく、より良い解決策は、すべてのグローバルデータを含むグローバルオブジェクトを作成することです。次に、この共有グローバルデータに実際にアクセスする必要があるクラスへのスマートポインターを渡します。例:

class GlobalData
{
public:
    int ticks_;
};   


//Other file
class ThatNeedsGlobalData
{
public:
ThatNeedsGlobalData(std::shared_ptr<GlobalData> globalData);
};

これはあなたにいくつかのトラブルを救うでしょう。

幸運を!

2
mantler

これまでのようにグローバル変数を使用しようとするときに注意する必要があることがいくつかあります。

  1. GobalInformation.hに含まれるヘッダーファイルに含まれるすべてのヘッダーファイルも#ifndefs内に含まれていることを確認してください。 (mapinformation.hが表示されなかったので、実行したと思います)

  2. CPPと同様に、Cコンパイラも異なる変換単位(異なるC/CPPファイル)の変数の初期化の順序を保証しません。したがって、ヘッダーファイルを次のように宣言します

    //GlobalInformation.h
    
    namespace gi {
        extern MapInformation mapInf;
    };
    
  3. 呼び出されることがわかっている関数では、最初に変数を初期化します。このようにして、レイジー初期化はCでも実現できます。

1
Guru Govindan