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

Mas*_*Man 4 c++ containers global-variables c++03

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

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

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

int main() {}
Run Code Online (Sandbox Code Playgroud)

编译错误:

prog.cpp:6:1: error: 'Aries' does not name a type
Run Code Online (Sandbox Code Playgroud)

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

vector<string> Aries = { "Taurus" };
Run Code Online (Sandbox Code Playgroud)

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

我尝试在StackOverflow上搜索,看看之前是否已经回答了这个问题,但是只发现了这些帖子:C++中的全局对象,在C++定义全局常量,这对此没有帮助.

Zet*_*eta 10

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

std::vector<string> Aries;

/* ... */

int main() {
    Aries.push_back("Taurus");
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

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

单个值

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

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

/* ... */

int main() { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

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

多个不同的价值

现在这有点棘手了.您希望vector使用合适的构造函数填充.std::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&) 请注意,所有这些实际上都将分配器作为附加的最后一个参数,但这不是我们关注的问题.

我们可以忘记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));
Run Code Online (Sandbox Code Playgroud)

请注意begin并且end没有必要 - 我们可以简单地使用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());
Run Code Online (Sandbox Code Playgroud)

此示例使用复制构造函数和范围构造函数.您还可以创建一个临时矢量并用于std::vector<T>::push_back在函数中填充它.


Mas*_*Man 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;
}
Run Code Online (Sandbox Code Playgroud)

产量

Taurus
Leo
Run Code Online (Sandbox Code Playgroud)

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

  • 我很惊讶,但对此解决方案感到害怕.有一个upvote;) (4认同)

小智 5

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

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