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 上搜索以查看之前是否已回答过此问题,但仅遇到以下帖子:C++ 中的全局对象、C++中的定义全局常量,但这无助于回答这个问题。

4

4 回答 4

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)withs == 1t == "Taurus"

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

/* ... */

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

如果您多次需要相同的值,您可以简单地调整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));

请注意,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());

此示例同时使用复制构造函数和范围构造函数。您还可以创建一个临时向量并用于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 回答