Что это за неожиданное поведение std :: vector? - PullRequest
1 голос
/ 01 февраля 2012

Я нашел кое-что удивительное в std::vector, о котором я думал, что хотел бы спросить здесь, чтобы, надеюсь, получить интересные ответы.

Приведенный ниже код просто копирует строку в символьный вектор и печатает содержимое вектора двумя способами.

#include <vector>
#include <string>
#include <iostream>

int main()
{
    std::string s("some string");
    std::vector<char> v;
    v.reserve(s.size()+1);

    // copy using index operator
    for (std::size_t i=0; i<=s.size(); ++i)
        v[i] = s[i];

    std::cout << "&v[0]:     " << &v[0] << "\n";
    std::cout << "begin/end: " << std::string(v.begin(), v.end()) << "\n";

    // copy using push_back
    for (std::size_t i=0; i<=s.size(); ++i)
        v.push_back(s[i]);

    std::cout << "&v[0]:     " << &v[0] << "\n";
    std::cout << "begin/end: " << std::string(v.begin(), v.end()) << "\n";

    return 0;
}

Сборка и запуск это дает:

$ g++ main.cpp -o v && ./v
&v[0]:     some string
begin/end: 
&v[0]:     some string
begin/end: some string

Я ожидал, что в обоих случаях она будет правильно печатать строку , но при назначении символа за символом с помощью оператора индекса ничего не печатается при использовании begin() и end() итераторы .

Почему end() не обновляется при использовании []? Если это умышленно, то по какой причине оно работает так?

Есть ли разумное объяснение этому поведению? :)

Пока я пробовал это только с gcc 4.6.1.

Ответы [ 2 ]

11 голосов
/ 01 февраля 2012

Типичный пример неопределенного поведения.

Вам разрешено только когда-либо обращаться к элементам по индексу (используя operator[]) от 0 до v.size()-1 (включено).

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

5 голосов
/ 01 февраля 2012

В первом случае у вас неопределенное поведение.reserve устанавливает емкость , но оставляет размер равным нулю.Затем ваш цикл записывает в недопустимые места за концом вектора.Печать с использованием (недопустимого) указателя, по-видимому, работает (хотя это и не гарантируется), поскольку вы записали строку в память, на которую она указывает;печать с использованием диапазона итератора ничего не печатает, поскольку вектор по-прежнему пуст.

Второй цикл корректно увеличивает размер каждый раз, так что вектор фактически содержит ожидаемое содержимое.

Почему end () не обновляется при использовании []?Если это сделано намеренно, то по какой причине он работает следующим образом?

[] должен быть максимально быстрым, поэтому проверка диапазона не производится.Если вы хотите проверить диапазон, используйте at(), что вызовет исключение при доступе вне диапазона.Если вы хотите изменить размер массива, вы должны сделать это самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...