Как настроить глобальный контейнер (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 ++, что не помогло ответить на это.

4

Решение

В то время как объявления и инициализации вне функции (такие как main) нет проблем, вы не можете иметь код вне функций. Вам нужно либо установить значение прямо при инициализации (как в C ++ 11), либо заполнить глобальный объект в main:

std::vector<string> Aries;

/* ... */

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

Другие способы (без заполнения вектора в основном)

Отдельные значения

Есть и другие способы, которые не нужны .push_back или другой код в основном. Например, если Aries должен содержать только один элемент, вы можете использовать std::vector<T>::vector(size_t s, T t) с s == 1 а также t == "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 заполнить его в функции.

10

Другие решения

Я нашел изящный обходной путь для «инициализации» глобальных контейнеров STL C ++ 03 (и, действительно, для выполнения кода «глобально» раньше 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

Единственная реальная проблема, если вы можете это так назвать, — это дополнительная глобальная переменная.

9

По моему опыту, это «удивительное, но ужасающее» решение (шляпный наконечник) непредсказуемо. Ваша инициализация выполняется во время загрузки. У вас нет гарантии как загрузить ЗАКАЗ. Таким образом, все, что использует этот контейнер, должно быть либо в том же модуле, либо каким-то образом гарантировать, что модуль будет загружен до того, как они получат доступ к контейнеру. В противном случае конструктор контейнера не запустится, но ваш код с радостью вызывает его методы доступа.

Когда он идет не так, он идет очень плохо, и ошибка зависит от компилятора, платформы и фазы луны — во всех случаях не дает ни малейшего понятия о том, что пошло на юг.

5

И просто для полноты, это решение использует конструктор пары итераторов и простой старый инициализатор массива.

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

Это может быть понятнее, но все же вызывает больше конструкторов копирования.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector