如何设置全局容器(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上搜索,看看以前是否有人回答过这个问题,但只看到了以下帖子:C++中的全局对象,C++中的定义全局常量,这对回答这个问题没有帮助。

我找到了一个巧妙的解决方法来"初始化"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

唯一真正的问题,如果你可以这么说的话,就是额外的全局变量。

虽然函数(如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&)请注意,它们实际上都将分配器作为附加的最后一个参数,但这不是我们关心的问题

我们可以忘记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在函数中填充它。

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

当它出错时,它就会出错,而且错误取决于编译器、平台和月球相位——在所有情况下,都没有给出任何关于南下的线索。

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

#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;
}

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

相关内容

  • 没有找到相关文章

最新更新