C ++ STL Контейнеры и правильность указателя - PullRequest
1 голос
/ 05 декабря 2010

Рассмотрим этот кусок кода:

Uint counter = 0;

int* p1;
int* p2;

deque<int>  dequeInstance;
vector<int> vectorInstance;

dequeInstance.push_back(3);
dequeInstance.push_back(7);

p1 = &dequeInstance.back();

dequeInstance.push_back(17);

p2 = &dequeInstance.back();

if(*p1 == !7)
    ++counter;

if(*p2 == !17)
    ++counter;

vectorInstance.push_back(3);
vectorInstance.push_back(7);

p1 = &vectorInstance.back();

vectorInstance.push_back(17);

p2 = &vectorInstance.back();

if(*p1 == !7)
    ++counter;

if(*p2 == !17)
    ++counter;



return counter;

Я ожидал, что когда я передвину третий элемент в конец вектора, указатель на второй элемент будет недействительным, так как я понимаю, что std :: vector - это прямой массив, который стирается и воссоздали каждый раз, когда его модифицировали. Однако в конце этого кода «counter» равен нулю.

Что мне здесь не хватает?

Ответы [ 2 ]

5 голосов
/ 05 декабря 2010

Надеюсь, что для производительности std::vector не «стирается и воссоздается каждый раз, когда изменяется».

Вектор имеет capacity, который может превышать его size, что означает, что он может выделить больше памяти, чем реально используется. Когда вы push_back, перераспределение произойдет только в том случае, если новый размер больше, чем старая емкость, и в этом случае , итераторы будут недействительными.

В вашем случае вам следует проверить значение capacity сразу после создания экземпляра std::vector. Вы увидите, что оно, без сомнения, больше 3, поэтому ни один из ваших вызовов push_back не вызывает перераспределение, и все итераторы остаются действительными.

Также обратите внимание, что std::vector предоставляет функцию-член reserve, которая позволяет вам контролировать емкость вектора. Это действительно полезно, когда вы знаете, сколько элементов предполагается вставить, чтобы избежать скрытого перераспределения.

2 голосов
/ 05 декабря 2010

Хорошо, у вас есть несколько проблем.Во-первых,! N = 0, если n = 0, а затем он равен 1. Поэтому счетчик никогда не увеличивается.

Во-вторых, вектор не обязательно уничтожает содержимое, когда вы нажимаете на новый элемент.Вектор имеет 2 "размера".1 - количество элементов в векторе, 2 - количество выделенной памяти.Вектор перераспределяется и копируется только тогда, когда объем выделенной памяти заканчивается.

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

Вы не используете итераторы, поэтому они не становятся недействительными.Вы используете указатели, а они просто указывают на область памяти.То, что эта память не выделена, не означает, что указатель недействителен.Это одна из главных опасностей, с которой C / C ++ может вас оставить.Удостоверьтесь, что вы не делаете подобные вещи, так как вы вызываете «неопределенное поведение», которое может сделать что угодно от «не вызывать никаких проблем и, казалось бы, работать» до «ужасного сбоя и сбить вашу операционную систему опасным способом».

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