关于c ++:如何设置全局容器(C ++ 03)?

How to setup a global container (C++03)?

我想定义一个全局容器(C++ 03),这是我尝试过的一个示例代码,不起作用。

1
2
3
4
5
6
7
8
#include <vector>
#include <string>
using namespace std;

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

int main() {}

编译错误:

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

似乎我可以定义一个空的全局向量,但不能填充它。看起来像在C++ 03中,我也不能指定一个初始化器,例如:

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

我在这里犯了错误,或者我该如何解决这个问题?

我尝试在StAdvExcel上搜索,看看这是否已经被回答过,但是只遇到了这些问题:C++中的全局对象,在C++中定义全局常量,这并没有帮助回答这个问题。


虽然函数外部的声明和初始化(如main)没有问题,但函数外部不能有代码。您需要在初始化时设置值(如C++ 11),或者在主体中填充您的全局对象:

1
2
3
4
5
6
7
8
std::vector<string> Aries;

/* ... */

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

其他方式(不填充主向量)单值

还有其他方法不需要.push_back或主代码中的其他代码。例如,如果Aries只包含一个项目,您可以将std::vector::vector(size_t s, T t)s == 1t =="Taurus"一起使用:

1
2
3
4
5
std::vector<string> Aries(1,"Taurus");

/* ... */

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

如果多次需要相同的值,可以简单地调整s

多个不同值

现在这变得有点棘手了。您希望使用合适的构造函数来填充vector。EDCOX1,8,在C++ 03中提供了四种不同的构造函数:

  • std::vector::vector()
  • std::vector::vector(size_t, T = T())
  • template std::vector::vector(InputIt, InputIt)
  • std::vector::vector(const vector&)注意,它们实际上都将一个分配器作为附加的最后一个参数,但这不是我们关心的问题。
  • 我们可以忘记std::vector::vector(),因为我们想用值填充向量,而且std::vector::vector(size_t, T)不适合,因为我们需要不同的值。剩下的是模板化构造函数和复制构造函数。下面的示例演示如何使用模板化构造函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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));

    注意,beginend不是必要的,我们可以简单地使用Aries(values, values+3)。然而,事情往往会发生变化,并且经常会添加或删除一个值。如果您忘记更改偏移量3,您将忘记values的入口或跨界。

    然而,这个解决方案引入了一个新的全局变量,这并不是很好。让我们后退一步。我们需要values,因为我们想要使用std::vector::vector(InputIt, InputIt),这需要一个有效的范围。在使用构造函数时,范围必须是已知的,所以它必须是全局的。诅咒!但是请注意:我们的工具箱仍然包含一个构造函数,即复制构造函数。为了使用它,我们创建了一个附加功能:

    1
    2
    3
    4
    5
    6
    7
    8
    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::push_back将其填充到函数中。


    我找到了一个整洁的解决方案来"初始化"C++ 03全局STL容器(并且实际上是在EDCOX1(23)之前)全局执行代码。这将使用逗号运算符。见例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #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;
    }

    产量

    1
    2
    Taurus
    Leo

    唯一真正的问题是额外的全局变量。


    我的经验是,这种"惊人但又可怕"(帽子提示)的解决方案是不可预测的。您的初始化在加载时运行。你方不能保证装船。因此,使用该容器的所有内容都必须在同一个模块中,或者以某种方式保证在访问该容器之前加载该模块。否则,容器构造函数还没有运行,但是您的代码很乐意调用它的访问器。

    当它出错时,它就会出错,而且错误是编译器、平台和与月球相关的阶段——在所有情况下,都不会给出最遥远的线索来说明什么是向南的。


    为了完整性,这个解决方案使用迭代器对构造函数和普通的旧数组初始值设定项。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #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;
    }

    这可能更清楚,但它调用了更多的复制构造函数。