Есть ли способ инициализировать объект из внешней области во внутренней области? - PullRequest
0 голосов
/ 15 октября 2010

Например:

int main()
{
    {
        // I want this array to be part of the inner scope
        string s[] = {"Ben","Joe","Bob","Matt"};

        // And I want to use it to initialize this vector, but I want this
        // vector to be visible in the outer scope
        vector<string> names(s,s+4);
    }
}

Есть ли способ сделать это?

Ответы [ 6 ]

4 голосов
/ 15 октября 2010

Если вы хотите, чтобы вектор был виден во внешней области, вы должны объявить его во внешней области.Это означает, что вы также должны инициализировать его там.Единственный способ объявить это без инициализации - использовать указатель:

int main()
{
  vector<string> * names = 0;

  {
    string s[] = {"Ben", "Joe", "Bob", "Matt"};
    names = new vector<string>(s, s+4);
  }

  // ...
  delete names;
}
1 голос
/ 15 октября 2010
int main()
{
    vector<string> names;
    {       
        string s[] = {"Ben","Joe","Bob","Matt"};
        names.assign(s,s+4);
    }
}
0 голосов
/ 17 марта 2011

Поскольку я задал этот вопрос, я нашел гораздо лучший способ сделать это, используя лямбды:

int main()
{
    std::vector<std::string> v = []() -> std::vector<std::string> {
        std::string s[] = {"Ben","Joe","Bob","Matt"};
        int cnt = sizeof(s)/sizeof(s[0]);
        return std::vector<string>(s,s+cnt);
    }();
}
0 голосов
/ 17 марта 2011

Нет способа сделать именно то, что вы просили. Как указали другие люди, существует несколько возможностей:

  1. Объявите вектор перед внутренней областью действия и заполните его во время. Это имеет недостаток в том, что вектор немного висит пустым, что не является хорошим стилем, и могут быть небольшие, небольшие издержки, если инициализировать его позже, а не конструктором, но ни один из них не должен иметь большого значения, так как вектор должен быть построен в какой-то момент в любом случае.

    // вставьте сюда пример кода, извлеченный из другого ответа (?)

  2. Объявите scoped_ptr (или const auto_ptr, или обычный указатель) перед внутренней областью, и new вектор во внутренней области, инициализируя его с помощью конструктора, и назначьте его указателю , Это почти не имеет недостатков. Вы должны привыкнуть к использованию ->, а не. но большинство программ на C ++ все равно должны делать это везде. Существует небольшой риск, что вы будете случайно использовать нераспределенный указатель перед внутренней областью, но он должен немедленно вызвать исключение, поэтому вы должны заметить.

    // вставьте сюда пример кода, извлеченный из другого ответа (?)

  3. Оберните в функцию всю внутреннюю область видимости или только строковый массив. Это похоже на сложность, но, честно говоря, я очень редко сожалел о постоянной инициализации в четко названной функции. Функция может либо возвращать массив, либо возвращать вектор напрямую (в зависимости от того, действительно ли вам нужны эти данные во внутренней области видимости или просто хотите избежать их загрязнения внешней областью видимости). В зависимости от того, как вы идете, это может выглядеть примерно так:

    vector MyFriends () { const string s [] = {"Бен", "Джо", "Боб", "Мэтт"}; возвращаемый вектор (s, s + (sizeof (s) / sizeof (s [0]))); // TODO: улучшить счет // Обратите внимание на использование оптимизации возвращаемого значения // Вероятно, это не имеет значения, но если вы заботитесь, компиляторы могут пропустить один или оба // из подразумеваемых временных векторных объектов. } * * Тысяча двадцать-один

    int main () { { // Делаем вещи // Если MyFriends зависит от материала, возможно, переместите материал в эту функцию, если это возможно // Если материалу просто нужен доступ к возвращаемому значению MyFriends, вызовите его снова здесь } вектор vec (MYFriends ());

    // Другие вещи }

  4. Если вы хотите инициализировать вектор, как в примере 3, я думаю, что C ++ 0x поддерживает специальный синтаксис для этого (??)

    // Предоставить пример

0 голосов
/ 15 октября 2010

Несмотря на строгую инициализацию вектора, если вы хотите, чтобы ваш объект был автоматически, а не динамически размещен, вы можете поменять его местами с временным:

{
    vector<string> names;

    {
        string s[] = {"Ben","Joe","Bob","Matt"};

        vector<string> init (s,s+4)

        swap ( names, init );
    }
}

Хотя основные копии продолжаются (Литералы char *, скопированные для создания std :: strings в массиве, затем std :: strings в массиве, скопированном в вектор), своп избегает копирования строк из init в имена.

0 голосов
/ 15 октября 2010

Упоминание ldx об указателях дало мне идею.Я никогда раньше не использовал shared_ptr, но я подумал, что это может быть решением, поэтому я посмотрел их и нашел решение:

Edit: изменено на auto_ptr

int main()
{
    auto_ptr<vector<string> > vsptr;

    {
        string s[] = {"Ben", "Joe", "Bob", "Matt"};
        int cnt = sizeof(s)/sizeof(string);

        vsptr = auto_ptr<vector<string> >(new vector<string>(s,s+cnt));
    }

    vector<string> &names = *vsptr;
}

Я протестировал его с классом, который объявляет его конструкторы, назначения и деструкторы, и есть только одна конструкция по умолчанию и одно уничтожение.Конечно, это требует повышения, если ваш компилятор еще не реализует tr1, но какой компилятор, чёрт побери, этого не делает?

...