#c #stl #reference #vector
#c #stl #ссылка #вектор
Вопрос:
Меня всегда немного смущало, как контейнеры STL (vector, list, map …) хранят значения. Хранят ли они ссылки на значения, которые я передаю, или они копируют / копируют конструкцию сохраняют сами значения?
Например,
int i;
vector<int> vec;
vec.push_back(i);
// does amp;(vec[0]) == amp;i;
и
class abc;
abc inst;
vector<abc> vec;
vec.push_back(inst);
// does amp;(vec[0]) == amp;inst;
Спасибо
Комментарии:
1. На мой взгляд, у вас есть то, что выглядит как рабочий код, который будет проверять ответ (с небольшим изменением, чтобы сделать комментарий условным). Запустите его и посмотрите! Я почти уверен, что они копируют, конструируют и сохраняют.
Ответ №1:
Контейнеры STL копируют-конструируют и сохраняют передаваемые вами значения. Если вы хотите хранить объекты в контейнере, не копируя их, я бы предложил сохранить указатель на объект в контейнере:
class abc;
abc inst;
vector<abc *> vec;
vec.push_back(amp;inst);
Это наиболее логичный способ реализации контейнерных классов для предотвращения случайного сохранения ссылок на переменные в несуществующих фреймах стека. Рассмотрим:
class Widget {
public:
void AddToVector(int i) {
v.push_back(i);
}
private:
vector<int> v;
};
Хранить ссылку на i
было бы опасно, поскольку вы ссылались бы на ячейку памяти локальной переменной после возврата из метода, в котором она была определена.
Комментарии:
1. Вы не можете создавать контейнеры create, которые хранят ссылки на C . Аргумент типа, передаваемый контейнеру, должен быть присваиваемым. Ссылки не могут быть назначены, они инициализируются объектом, но не могут быть назначены ссылке на другой объект после построения. Таким образом, ссылочные типы не соответствуют требованиям к типу, которые будут использоваться внутри контейнеров. Если вы хотите иметь ту же семантику (или настолько близкую, насколько это возможно), вы должны предоставить ссылочную оболочку (boost::ref/boost::cref)
2. @dribeas: Этот ответ объясняет, почему нет , объясняя риски гипотетической реализации.
Ответ №2:
Это зависит от вашего типа. Если это простой тип значений и его дешево копировать, то сохранение значений, вероятно, является решением. С другой стороны, если это ссылочный тип или его дорого копировать, вам лучше сохранить интеллектуальный указатель (не auto_ptr, поскольку его специальная семантика копирования не позволяет хранить его в контейнере. Выберите shared_ptr). С простым указателем вы рискуете утечкой памяти и доступом к освобожденной памяти, в то время как со ссылками вы рискуете последним. Интеллектуальный указатель позволяет избежать обоих.
Комментарии:
1. 1 об использовании интеллектуальных указателей внутри контейнеров для работы с памятью. Другим вариантом может быть использование библиотеки типа Boost Pointer Container для освобождения ресурсов
2. Это не то, о чем спрашивает OP. Он хочет знать, копируют ли сами классы контейнера значение, когда оно помещается в контейнер. Ответ таков: да, они это делают — вот почему хранение указателей может быть полезным, если копирование конкретного рассматриваемого типа обходится дорого.
3. И хранить голые указатели совершенно нормально, если вы знаете, что делаете, и убираете за собой.