Я хочу создать вектор объектов, но не хочу размещать их в куче. Я хочу разместить их в памяти стека. Но я сталкиваюсь с проблемами.
struct Object { int x; Object(int x) { this->x = x; } };
int main() {
std::vector<Object*> v;
for (int i = 0; i < 5; i++) {
Object o (i);
v.push_back(&o);
std::cout << &o << std::endl; // keeps printing the same mem address...
// ...implying that these are all the same object
}
}
У меня есть подозрение, что объект удаляет себя после выхода из области видимости после каждой итерации цикла for.
Теперь я знаю, что вы можете просто сделать v.push_back(new Object(i))
для каждой итерации, и это будет работать. Однако я не хочу, чтобы эти объекты размещались в куче, где мне нужно вручную управлять памятью.
Вы в основном правы, что «объект [разрушается] после выхода из области видимости». Это также сбивает с толку из-за того, что вы печатаете. Основываясь на том, как компилятор распределяет переменные с «длительностью автоматического хранения» в цикле, переменная стека Object o
всегда имеет один и тот же адрес.
std::vector<Object*> v;
for (int i = 0; i < 5; i++) {
Object o (i);
v.push_back(&o);
// Variable o still exists on the stack
std::cout << &o << std::endl; // Prints the address of the automatic variable 'o'
}
// At this point, no objects exist; they all went out of scope
// every pointer in v is invalid, pointing to the "ghost" of a destoryed object.
Я думаю, что простой подход, который вы ищете, это просто создать вектор объектов.
std::vector<Object> v;
for (int i = 0; i < 5; i++) {
v.push_back(Object(i));
std::cout << &(v.back()) << std::endl; // Prints the address of the Object just added
}
Тем не менее, вы должны понимать, что std::vector<Object>
будет правильно управлять временем жизни вашего объекта, уничтожая объекты, когда сам вектор выходит из области видимости. Но объекты на самом деле хранятся в бесплатном магазине. Это нормально.
Здесь вывод от идеона при компиляции и запуске с вектором объектов:
0x8e66008
0x8e6601c
0x8e66030
0x8e66034
0x8e66050
Если вы действительно не хотите размещать их в стеке, а просто хотите управлять памятью, вам действительно потребуется несколько часов, чтобы заполнить пробелы в знаниях.
В частности, получение достаточного количества знаний о RAII имеет решающее значение для эффективного использования C ++ и C ++ 11. я очень рекомендую Справочник по языку C ++, 4-е издание. 4-е издание важно, потому что оно сильно отличается от 3-го издания.
В нем он покажет вам, что скорее всего захочет использовать std::vector<std::unique_ptr>
для этой конкретной проблемы, или чтобы сделать Object
сам управляемый объект (с реализованной семантикой перемещения).
Вектор удаляется, а не объекты.
Следующее означает, что вы сохраняете указатели в векторе v
:
std::vector<Object*> v;
Вы могли бы сделать это:
std::vector<Object> v;
в этом случае вы получаете много объектов, но затем вы получаете копии своих объектов, что иногда либо невозможно, либо не то, что вы хотите (хотя более новая версия компилятора C ++ может сделать перемещение вместо копии, но я этого не делаю думаю, что будет работать в этом случае …)
Другой способ, если вы хотите, чтобы объекты распределялись, а затем автоматически удалялись, — это использовать умный указатель.
#include <memory>
std::vector<std::shared_ptr<Object> > v;
В этом случае объекты распределяются вами и освобождаются всякий раз, когда вектор удаляется.
Однако ваша проблема в том, что вы инициализируете объекты в стеке и присваиваете этот указатель стека вашему вектору. Я хотел бы изобразить, что ваш отпечаток показывает, что указатель всегда один и тот же … это означает, что предыдущий объект уничтожается, а новый создается на каждой итерации.
Поэтому я бы заменил эти строки:
std::vector<Object*> v;
Object o (i);
v.push_back(&o);
Примерно так:
std::vector<std::shared_ptr<Object> > v;
std::shared<Object> o(new Object(i));
v.push_back(o);
Если вы ничего не знаете об общих указателях, я предлагаю вам прочитать их. Это очень полезно, когда вы выделяете объекты new
, Также есть несколько ловушек с так называемыми циклическими ссылками (т. Е. Посмотрите и на weak_ptr). Но таким образом вам не нужно управлять памятью, и у вас есть хорошие указатели.
Если вы предпочитаете решение с Объектом само по себе, это будет что-то вроде этого:
std::vector<Object> v;
Object o(i);
v.push_back(o);
Таким образом, вы избегаете кучи, тем не менее, вы делаете копии каждый раз, когда вы нажимаете (или перемещаетесь). Так что, если ваши объекты большие, это не очень хорошая идея.
Кроме того, если в вашем объекте есть указатели, использование интеллектуальных указателей также очень вам поможет. Так что в любом случае это хорошая идея, чтобы узнать о них.