如何设置全局容器(C ++ 03)?

时间:2012-12-16 08:57:59

标签: c++ global-variables containers c++03

我想定义一个全局容器(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 个答案:

答案 0 :(得分:10)

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

std::vector<string> Aries;

/* ... */

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

其他方式(不在main中填充向量)

单个值

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

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

/* ... */

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

如果您需要多次使用相同的值,则只需调整s

多个不同的值

现在这有点棘手了。您希望使用合适的构造函数填充vectorstd::vector<T>在C ++ 03中提供了四种不同的构造函数:

  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&) 请注意,所有这些实际上都将分配器作为额外的最后一个参数,但这不是我们关注的问题。
  5. 我们可以忘记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));
    

    请注意,beginend不是必需的 - 我们可以简单地使用Aries(values, values+3)。但是,事情往往会发生变化,通常会添加一个值或删除一个值。如果您忘记更改偏移量3,则会忘记values的条目或跨越边界。

    然而,这个解决方案引入了一个新的全局变量,它不是那么好。让我们退后一步。我们需要values,因为我们想要使用需要有效范围的std::vector<T>::vector(InputIt, InputIt)。并且在我们使用构造函数时必须知道范围,因此它需要是全局的。诅咒!但是看到:我们的工具箱仍然包含一个构造函数,即复制构造函数。为了使用它,我们创建了一个额外的功能:

    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在函数中填充它。

答案 1 :(得分:9)

我找到了一个简洁的解决方法来“初始化”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

唯一真正的问题,如果你可以称之为,那就是额外的全局变量。

答案 2 :(得分:5)

我的经验是,这种“惊人但又可怕”(帽子提示)的解决方案是不可预测的。您的初始化在加载时运行。您无法保证加载ORDER。因此,使用该容器的所有内容必须位于同一模块中,或者以某种方式保证模块在访问容器之前已加载。否则,容器构造函数尚未运行,但您的代码很乐意调用其访问器。

当它出错时,它会出错,并且错误是依赖于月亮的编译器,平台和阶段 - 在所有情况下都不会给出最南端的线索。

答案 3 :(得分: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;
}

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