если хочется работать с указателями и stl-ем, то
лучше пихать в vector SmartPtr, примеры можно найти в boost. Тогда только об удалении можно не думать. Хотя в кривых руках и калькулятор зависнет.
std::vector. как правильно упаковать в вектор объект
От:
Аноним
Дата:
04.09.06 14:27
Оценка:
Доброго времени суток,
столкнулся с интересной проблемой при использовании std::vector. Суть проблемы (сперва код):
class B
{
public:
BOOL ExecuteThread();
.
.
.
protected:
virtual DWORD vThreadProc();
};
класс просто инициализирует поток, а затем в нужный момент его запускает. Далее
А теперь суть проблемы. Предположит во время выполнения инициализируются 3 объекта B с различными параметрами, а соответсвенно и 3 различных потока.
Метод A::Init() будет вызван 3 раза, а все объекты упакуются в вектор. Вот тут и проблема: в вектор правильно пишется только первый объект, остадбные записываются (увеличивается размер элементов вектора, но внутри ячейки лежит мусор).
Курез ситуации в том, что исходя из вышепнаписанного должен заработаль только первый поток, посредством B::ExecuteThread(), но они запускаются все, тесть метод A::Start() отрабатывает без ошибок, а итератор возвращает данные правильно.
Зато в деструкторе первый объет уничтожается нормально,а на втором всё падает с Access Violation, тоесть опять в векторе виден только один элемент (правильно виден). Размер вектора при вызове деструктора тоже 3.
В чём моя ошибка, может уже кто сталкивался? Операторы присваивания и конструкторы копирования класса B написаны и отлично работают.
Может нужны какие-то дополниетельные инициализации самого вектора???
Заранее благодарен всем откликнувшимся.
Добавлено форматирование — Кодт
Re: std::vector. как правильно упаковать в вектор объект
От:
Аноним
Дата:
04.09.06 14:56
Оценка:
Здравствуйте, Аноним, Вы писали:
А>class A
А>{
А> public:
А> A();
А> ~A();
А> BOOL Init();
А> BOOL Start();
А> .
А> .
А> .
А> private:
А> vector<B> vec;
А>};
[ кусь ]
А>A::~A()
А>{
А> vector<B>::iterator iter = vec.begin(); // Этот код не может не падать. ВЕКТОР УДАЛИТ ЭЛЕМЕНТЫ САМ.
А> while(iter != vec.end())
А> {
А> delete iter;
А> iter++;
А> }
А>}
А>BOOL A::Init(параметры)
А>{
А> B *pB;
А> pB = new B(параметры); // Зачем создавать по new? на стеке тоже пректасно можно создавать элементы.
А> vec.push_back(*pB); // Я бы написал vec.push_back( B(параметры) );
А> delete pB;
А>}
[кусь]
А>Операторы присваивания и конструкторы копирования класса B написаны и отлично работают.
Код
B( const B & )
const B operator = ( const B & )
~B();
В студию.
Re[2]: std::vector. как правильно упаковать в вектор объект
Здравствуйте, pavel_turbin, Вы писали:
_>если хочется работать с указателями и stl-ем, то _>лучше пихать в vector SmartPtr, примеры можно найти в boost. Тогда только об удалении можно не думать. Хотя в кривых руках и калькулятор зависнет.
А если охота возиться с сырыми указателями то вектор нужно инстанцировать указателями на B, типа такого ...
std::vector<B *> SomeObject;
Re[2]: std::vector. как правильно упаковать в вектор объект
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Аноним, Вы писали:
А>
А>>class A
А>>{
А>> public:
А>> A();
А>> ~A();
А>> BOOL Init();
А>> BOOL Start();
А>> .
А>> .
А>> .
А>> private:
А>> vector<B> vec;
А>>};
А>[ кусь ]
А>>A::~A()
А>>{
А>А> vector<B>::iterator iter = vec.begin(); // Этот код не может не падать. ВЕКТОР УДАЛИТ ЭЛЕМЕНТЫ САМ.
А>> while(iter != vec.end())
А>> {
А>> delete iter;
А>> iter++;
А>> }
А>>}
Можно уточнить, вектор удалит элементы сам путём вызова деструктора ~B() или как???
Просто если в B имеет место динамическое выделение памяти, необходимо гарантировать её стопоцентное освобождение???
Да и вопрос остался. Падает только на втором элементе вектора, первый успешно удаляется!
А>>BOOL A::Init(параметры)
А>>{
А>> B *pB;
А>> pB = new B(параметры); // Зачем создавать по new? на стеке тоже пректасно можно создавать элементы.
А>> vec.push_back(*pB); // Я бы написал vec.push_back( B(параметры) );
А>> delete pB;
А>>}
Данный метод - это просто пример для обсуждения, в реально используемом классе нужно было гарантировать правильное создание объекта и инициализацию его параметров, поэтому создаётся динамически. Неудобно, но другого варинта не нашлось, пока....
А>
А>[кусь]
А>>Операторы присваивания и конструкторы копирования класса B написаны и отлично работают.
А>Код А>B( const B & ) А>const B operator = ( const B & ) А>~B(); А>В студию.
С удовольствием бы выкинул, но пример приводимый тут снят с разрабатываемой модели, а поэтому если выкидывать реализацию операторов, то придётся выкладывать и много сопутсвующего материала
да и ещё А>const B operator = ( const B & )
не слишком рекомендуется, лучше
B& operator= (const B& rhs), причины хорошо описаны Скотом Мейерсом (см. правило 15).
Re[3]: std::vector. как правильно упаковать в вектор объект
Здравствуйте, __GnoM, Вы писали:
А>>[ccode] А>>>class A А>>>{ А>>> public: А>>> A(); А>>> ~A(); А>>> BOOL Init(); А>>> BOOL Start(); А>>> . А>>> . А>>> . А>>> private: А>>> vector<B> vec; Элементы вектора хранятся по значению А>>>};
А>>>A::~A() А>>>{ А>>А> vector<B>::iterator iter = vec.begin(); // Этот код не может не падать. ВЕКТОР УДАЛИТ ЭЛЕМЕНТЫ САМ. А>>> while(iter != vec.end()) А>>> { А>>> delete iter; А>>> iter++; А>>> } А>>>}
__G>Можно уточнить, вектор удалит элементы сам путём вызова деструктора ~B() или как??? __G>Просто если в B имеет место динамическое выделение памяти, необходимо гарантировать её стопоцентное освобождение???
__G>Да и вопрос остался. Падает только на втором элементе вектора, первый успешно удаляется!
В vec элементы хранятся по значению, т.е. вектор сам их создает и уничтожает.
Поэтому руками удалять их _нельзя_, и этот while _нужно_ убрать. Иначе ошибка
будет возникать в деструкторе класса vector.
В вышепреведенном коде происходит следующее.
В векторе данные хранятся непрерывно одним блоком памяти. В используемой вами STL итератор
определен как указатель (в STLPort в отладочном режиме это не так, поэтому этот код c STLPort даже бы не скомпилировался).
В данном случае интератор, указывающий на начальный элемент вектора — это просто указатель
на блок памяти, выделенный классом vector. Поэтому первое удаление происходит нормально (да и то,
у других компиляторов здесь могла возникнуть ошибка из-за выделения по new[], а удалению по delete).
На следующей итерации итератор-указатель указывает на следующий элемент вектора, т.е. адрес
который находился внутри уже удаленного блока памяти.
Таким образом получается, что производится попытка освобождения памяти, начиная с адреса, с которого не выделялся ни один из блоков памяти, не говоря уже о том, что удаление блока памяти,
куда входил этот элемент вектора, уже произошло.
В результате — повреждение кучи с перспективой искать причины странных и непостоянно проявляющихся ошибок.
Можно сказать, что в данном случае вам еще повезло, что ошибка сразу возникает.
Так что либо в приведенном коде опечатки, либо автор кода не представляет,
что из себя представляет шаблонный класс вектора и как его можно использовать.
__G>Данный метод — это просто пример для обсуждения, в реально используемом классе нужно было гарантировать правильное создание объекта и инициализацию его параметров, поэтому создаётся динамически. Неудобно, но другого варинта не нашлось, пока....
Тогда лучше описать, какую задачу решаете по созданию объекта, может кто и лучше чего посоветует.
С уважением, Александр Авраменко.
Re[4]: std::vector. как правильно упаковать в вектор объект
Здравствуйте, Alex_Avr, Вы писали:
A_A>Здравствуйте, __GnoM, Вы писали:
А>>>[ccode] А>>>>class A А>>>>{ А>>>> public: А>>>> A(); А>>>> ~A(); А>>>> BOOL Init(); А>>>> BOOL Start(); А>>>> . А>>>> . А>>>> . А>>>> private: А>>>> vector<B> vec; Элементы вектора хранятся по значению А>>>>};
А>>>>A::~A() А>>>>{ А>>>А> vector<B>::iterator iter = vec.begin(); // Этот код не может не падать. ВЕКТОР УДАЛИТ ЭЛЕМЕНТЫ САМ. А>>>> while(iter != vec.end()) А>>>> { А>>>> delete iter; А>>>> iter++; А>>>> } А>>>>}
__G>>Можно уточнить, вектор удалит элементы сам путём вызова деструктора ~B() или как??? __G>>Просто если в B имеет место динамическое выделение памяти, необходимо гарантировать её стопоцентное освобождение???
__G>>Да и вопрос остался. Падает только на втором элементе вектора, первый успешно удаляется!
A_A>В vec элементы хранятся по значению, т.е. вектор сам их создает и уничтожает. A_A>Поэтому руками удалять их _нельзя_, и этот while _нужно_ убрать. Иначе ошибка A_A>будет возникать в деструкторе класса vector.
A_A>В вышепреведенном коде происходит следующее. A_A>В векторе данные хранятся непрерывно одним блоком памяти. В используемой вами STL итератор A_A>определен как указатель (в STLPort в отладочном режиме это не так, поэтому этот код c STLPort даже бы не скомпилировался).
A_A>В данном случае интератор, указывающий на начальный элемент вектора — это просто указатель A_A>на блок памяти, выделенный классом vector. Поэтому первое удаление происходит нормально (да и то, A_A>у других компиляторов здесь могла возникнуть ошибка из-за выделения по new[], а удалению по delete). A_A>На следующей итерации итератор-указатель указывает на следующий элемент вектора, т.е. адрес A_A>который находился внутри уже удаленного блока памяти.
A_A>Таким образом получается, что производится попытка освобождения памяти, начиная с адреса, с которого A_A>не выделялся ни один из блоков памяти, не говоря уже о том, что удаление блока памяти, A_A>куда входил этот элемент вектора, уже произошло.
A_A>В результате — повреждение кучи с перспективой искать причины странных и непостоянно проявляющихся ошибок. A_A>Можно сказать, что в данном случае вам еще повезло, что ошибка сразу возникает.
A_A>Так что либо в приведенном коде опечатки, либо автор кода не представляет, A_A>что из себя представляет шаблонный класс вектора и как его можно использовать.