4

グローバル コンテナー (C++03) を定義したいのですが、試したコード例を次に示しますが、うまくいきません。

#include <vector>
#include <string>
using namespace std;

vector<string> Aries;
Aries.push_back("Taurus");    // line 6

int main() {}

コンパイル エラー:

prog.cpp:6:1: error: 'Aries' does not name a type

空のグローバル ベクトルを定義できるようですが、それを埋めることはできません。C++03 のように見えますが、次のような初期化子も指定できません。

vector<string> Aries = { "Taurus" };

ここで間違いを犯しましたか、またはこの問題を回避するにはどうすればよいですか?

これが以前に回答されているかどうかを確認するために StackOverflow を検索しようとしましたが、これらの投稿に出くわしただけでした: global objects in C++Defining global constant in C++、これは回答に役立ちませんでした。

4

4 に答える 4

10

関数 ( などmain) の外側での宣言と初期化は問題ありませんが、関数の外側にコードを含めることはできません。初期化時に (C++11 のように) 値を設定するか、グローバル オブジェクトを main に入力する必要があります。

std::vector<string> Aries;

/* ... */

int main() {
    Aries.push_back("Taurus");
    /* ... */
}

その他の方法 (メインにベクターを設定せずに)

単一の値

必要のない他の方法.push_backや、メインの他のコードがあります。たとえば、Ariesアイテムが 1 つだけ含まれる場合は、 と を使用std::vector<T>::vector(size_t s, T t)できs == 1ますt == "Taurus"

std::vector<string> Aries(1, "Taurus");

/* ... */

int main() { /* ... */ }

同じ値が数回必要な場合は、単純に調整できますs

複数の固有値

ここで、これは少しトリッキーになります。vector適切なコンストラクターを使用して を設定します。std::vector<T>C++03 では、次の 4 つの異なるコンストラクターが提供されます。

  1. std::vector<T>::vector()
  2. std::vector<T>::vector(size_t, T = T())
  3. template <class InputIt> std::vector<T>::vector(InputIt, InputIt)
  4. std::vector<T>::vector(const vector&) それらはすべて、実際には追加の最後のパラメーターとしてアロケーターを取りますが、これは私たちの関心事ではないことに注意してください。

std::vector<T>::vector()ベクトルを値で埋めたいので、については忘れることができます。また、異なる値が必要なstd::vector<T>::vector(size_t, T)ため、適合しません。残っているのは、テンプレート化されたコンストラクターとコピー コンストラクターです。次の例は、テンプレート化されたコンストラクターの使用方法を示しています。

std::string const values[] = {"Taurus", "Ares", "Testos"};

template <class T, size_t N>
T* begin(T (&array)[N]){ // this is already in C++11, very helpful 
    return array;
}
template <class T, size_t N>
T* end(T (&array)[N]){
    return array+N;
}

std::vector<std::string> Aries(begin(values), end(values));

beginと は必須ではないことに注意してください。end単純に を使用できますAries(values, values+3)。ただし、状況は変化する傾向があり、多くの場合、値を追加したり削除したりします。オフセットを変更するのを忘れると3、エントリを忘れるか、境界を越えてしまいますvalues

ただし、このソリューションは新しいグローバル変数を導入しますが、これはあまり良くありません。一歩後退しましょう。有効な範囲が必要なvaluesを使用したかったので必要でした。std::vector<T>::vector(InputIt, InputIt)また、コンストラクターを使用するときに範囲がわかっている必要があるため、グローバルである必要があります。呪い!しかし、見てください: ツールボックスにはまだ 1 つのコンストラクター、コピー コンストラクターが含まれています。それを使用するために、追加の関数を作成します。

namespace {
    std::vector<std::string> initializer(){
        const std::string dummy_array[] = {"Taurus", "Ares", "Testos"};
        return std::vector<std::string>(begin(dummy_array), end(dummy_array));
    }
}

std::vector<std::string> Aries(initializer());

この例では、コピー コンストラクターと範囲コンストラクターの両方を使用しています。一時的なベクトルを作成し、std::vector<T>::push_backそれを関数に取り込むために使用することもできます。

于 2012-12-16T09:02:41.677 に答える
10

C++03 グローバル STL コンテナーを「初期化」する (そして実際にコードを「グローバル」に実行するmain()) ための巧妙な回避策を見つけました。これはコンマ演算子を使用します。例を参照してください:

#include <vector>
#include <string>
#include <iostream>
using namespace std;

vector<string> Aries;

// dummy variable initialization to setup the vector.
// using comma operator here to cause code execution in global scope.
int dummy = (Aries.push_back("Taurus"), Aries.push_back("Leo"), 0);

int main() {
    cout << Aries.at(0) << endl;
    cout << Aries.at(1) << endl;
}

出力

Taurus
Leo

唯一の本当の問題は、それを呼び出すことができる場合、余分なグローバル変数です。

于 2012-12-16T09:20:31.000 に答える
5

私の経験では、この「驚くべき、しかし恐ろしい」(ハット チップ) ソリューションは予測不可能です。初期化はロード時に実行されます。ORDER をロードする保証はありません。したがって、そのコンテナを使用するものはすべて同じモジュール内に存在するか、コンテナにアクセスする前にモジュールがロードされることを保証する必要があります。それ以外の場合、コンテナー コンストラクターは実行されていませんが、コードは喜んでそのアクセサーを呼び出します。

それがうまくいかない場合、それは非常にうまくいかず、エラーはコンパイラ、プラットフォーム、および月の位相に依存します-すべての場合、何が南に行ったかについての最も遠い手がかりを与えません.

于 2013-02-20T21:08:59.997 に答える
1

完全を期すために、このソリューションでは反復子ペア コンストラクターと単純な古い配列初期化子を使用します。

#include <vector>
#include <string>
#include <iostream>
using namespace std;

string contents[] = {"Taurus", "Leo"};
vector<string> Aries(contents, contents + sizeof contents/sizeof contents[0]);

int main() {
    cout << Aries.at(0) << endl;
    cout << Aries.at(1) << endl;
}

これはより明確かもしれませんが、より多くのコピー コンストラクターを呼び出します。

于 2013-02-21T01:24:34.543 に答える