class CPString
{
private:
CHAR* m_szStr;
public:
CPString();
~CPString();
VOID Set (CHAR* src);
CHAR* Get ();
DWORD Length () const;
CPString& operator = (CHAR* src);
};
//
// функции такие же как в форуме
//class CStringTable
{
public:
CPString* m_nTableName;
CPString** m_nNames;
CPString** m_nMessages;
CStringTable();
~CStringTable();
}
//
// здесь напишу только конструктор и деструктор.
//
CStringTable::CStringTable()
{
m_nTableName = new CPString();
m_nNames = new CPString*[99];
for (BYTE i = 0; i < 99; i++)
{
m_nNames[i] = new CPString();
}
m_nMessages = new CPString*[145];
for (BYTE i = 0; i < 145; i++)
{
m_nMessages[i] = new CPString();
}
};
CStringTable::~CStringTable()
{
delete m_nTableName;
for (BYTE i = 0; i < 99; i++)
{
delete m_nNames[i];
}
delete[] m_nNames;
for (BYTE i = 0; i < 145; i++)
{
delete m_nMessages[i];
}
delete[] m_nMessages;
};
Первый вопрос: в деструктор при delete m_nTable (и у остальных) для CPString вызовется деструктор или просто указатель в ноль установит?
Далее, в программе делаю vector<CStringTable*>.
vector<CStringTable*> m_vcStrings;
CStringTable* cNew1STable = new CStringTable();
m_vcStrings.push_back(cNew1STable);
CStringTable* cNew2STable = new CStringTable();
m_vcStrings.push_back(cNew2STable);
После использования мне вектор надо очистить
Так?
for (int i = 0; i < (int) m_vcStrings.size(); i++)
{
m_vcStrings[i]->~CStringTable();
}
m_vcStrings.clear();
или так?
for (int i = 0; i < (int) m_vcStrings.size(); i++)
{
delete m_vcStrings[i];
}
m_vcStrings.clear();
Или можно вообще этого не делать — vector<>::clear() сам очистит память от всего?
Ovl>class CPString
Ovl>{
Ovl>private:
Ovl> CHAR* m_szStr;
Ovl>public:
Ovl> CPString();
Ovl> ~CPString();
Ovl> VOID Set (CHAR* src);
Ovl> CHAR* Get ();
Ovl> DWORD Length () const;
Ovl> CPString& operator = (CHAR* src);
// Не хватает конструктора копирования.
// По умолчанию компилятор создаст copy-ctor дебильный, который скопирует указатель.
Ovl>};
Ovl>class CStringTable
Ovl>{
Ovl>public:
Ovl> CPString* m_nTableName;
// а смысл? Почему нельзя было сделать просто
CPString m_nTableName;
Ovl> CPString** m_nNames;
Ovl> CPString** m_nMessages;
// Тот же самый вопрос.
// И вообще, почему не векторы?
vector<CPString> m_nNames, m_nMessages;
Ovl> CStringTable();
Ovl> ~CStringTable();
// как насчет конструктора копирования?
// если даже он не нужен - сделай хотя бы заглушку, чтобы компилятор по рогам надавалprivate: CStringTable(CStringTable const&) { assert(!"Нафиг"); }
Ovl>}
Ovl>CStringTable::CStringTable()
Ovl>{
Ovl> m_nTableName = new CPString();
// члены - не-указатели - не нуждаются в лишнем new.
Ovl> m_nNames = new CPString*[99];
Ovl> for (BYTE i = 0; i < 99; i++)
Ovl> {
Ovl> m_nNames[i] = new CPString();
// смысл массива указателей - только если ты каждую строчку конструируешь отдельным образом
Ovl> }
Ovl> m_nMessages = new CPString*[145];
Ovl> for (BYTE i = 0; i < 145; i++)
Ovl> {
Ovl> m_nMessages[i] = new CPString();
Ovl> }
Ovl>};
Ovl>CStringTable::~CStringTable()
Ovl>{
Ovl> delete m_nTableName;
Ovl> for (BYTE i = 0; i < 99; i++)
Ovl> {
Ovl> delete m_nNames[i];
Ovl> }
Ovl> delete[] m_nNames;
Ovl> for (BYTE i = 0; i < 145; i++)
Ovl> {
Ovl> delete m_nMessages[i];
Ovl> }
Ovl> delete[] m_nMessages;
Ovl>};
Ovl>
Ovl>Первый вопрос: в деструктор при delete m_nTable (и у остальных) для CPString вызовется деструктор или просто указатель в ноль установит?
Наоборот: вызовется деструктор, освободится память, а указатель в ноль не встанет.
Ovl>Далее, в программе делаю vector<CStringTable*>.
Тоже вопрос: зачем вектор указателей?
Ovl>
Ovl>vector<CStringTable*> m_vcStrings;
Ovl>CStringTable* cNew1STable = new CStringTable();
Ovl>m_vcStrings.push_back(cNew1STable);
Ovl>CStringTable* cNew2STable = new CStringTable();
Ovl>m_vcStrings.push_back(cNew2STable);
Ovl>
Ovl>После использования мне вектор надо очистить
Ovl>Так? Ovl>
Ovl>for (int i = 0; i < (int) m_vcStrings.size(); i++)
Ovl>{
Ovl> m_vcStrings[i]->~CStringTable();
// нет!!!
// раз уж ты выделял память (new) то изволь освобождать (delete)
Ovl>}
Ovl>m_vcStrings.clear();
Ovl>
Ovl>или так? Ovl>
Ovl>for (int i = 0; i < (int) m_vcStrings.size(); i++)
Ovl>{
Ovl> delete m_vcStrings[i];
// так правильно.
Ovl>}
Ovl>m_vcStrings.clear();
Ovl>
Ovl>Или можно вообще этого не делать — vector<>::clear() сам очистит память от всего?
Он (грубо говоря) выполнит деструкторы указателей.
А это, фактически, деструктор целого числа. Что там разрушать?
Поэтому будет куча висячих объектов.
Ovl>Вызывает ли delete деструктор объекта?
Добрый день , Ovl, Вы писали:
Ovl>Добрый вечер.
...
Ovl>Первый вопрос: в деструктор при delete m_nTable (и у остальных) для CPString вызовется деструктор или просто указатель в ноль установит?
Для каждого объекта CPString сначала вызывается деструктор, затем овобождается память, который каждый из этих объектов занимал. Кстати для самого CPString я не увидел деструктора. Его нет, или ты его просто не привел?
Ovl>Далее, в программе делаю vector<CStringTable*>.
Ovl>
Ovl>vector<CStringTable*> m_vcStrings;
Ovl>CStringTable* cNew1STable = new CStringTable();
Ovl>m_vcStrings.push_back(cNew1STable);
Ovl>CStringTable* cNew2STable = new CStringTable();
Ovl>m_vcStrings.push_back(cNew2STable);
Ovl>
Ovl>После использования мне вектор надо очистить
Ovl>Так? Ovl>
Ovl>for (int i = 0; i < (int) m_vcStrings.size(); i++)
Ovl>{
Ovl> m_vcStrings[i]->~CStringTable();
Ovl>}
Ovl>m_vcStrings.clear();
Ovl>
Ни в коем случае. Деструкторы для объектов CStringTable конечно будут вызваны, но "сырая" память, в которой эти объекты размещались, не будет возвращена системе. Т.е. получаем memory leak.
Ovl>или так? Ovl>
Ovl>for (int i = 0; i < (int) m_vcStrings.size(); i++)
Ovl>{
Ovl> delete m_vcStrings[i];
Ovl>}
Ovl>m_vcStrings.clear();
Ovl>
можно и так...
А еще так:
В лоб:
for(vector<CStringTable*>::iterator it = m_vcStrings.begin(), itEnd = m_vcStrings.end(); it != itEnd; ++it )
delete *it;
Но есть и более изощренные методы
Например MaximE в этом топике
Ovl>Или можно вообще этого не делать — vector<>::clear() сам очистит память от всего?
Конечно нет.
Ovl>Вызывает ли delete деструктор объекта?
Всенепременно.
Ovl>Заранее спасибо
Здравствуйте, Кодт, Вы писали:
К>// Не хватает конструктора копирования. К>// По умолчанию компилятор создаст copy-ctor дебильный, который скопирует указатель.
Я хотел его сделать, но не знал как именно. Спасибо за пример
Ovl>>class CStringTable Ovl>>{ Ovl>>public: Ovl>> CPString* m_nTableName;
К>// а смысл? Почему нельзя было сделать просто К> CPString m_nTableName;
Ovl>> CPString** m_nNames; Ovl>> CPString** m_nMessages;
К>// Тот же самый вопрос. К>// И вообще, почему не векторы? К> vector<CPString> m_nNames, m_nMessages;
Я подумал, что вектор сохдает полную копию объекта и если его (объекта) размер изменяется (а для CPString это в порядке вещей), то это плохо будет. Вектор использует сам объект или только ссылку на него?
Ovl>> CStringTable(); Ovl>> ~CStringTable();
К>// как насчет конструктора копирования? К>// если даже он не нужен — сделай хотя бы заглушку, чтобы компилятор по рогам надавал
Обязательно, теперь знаю как.
Ovl>>CStringTable::CStringTable() Ovl>>{ Ovl>> m_nTableName = new CPString();
К>// члены — не-указатели — не нуждаются в лишнем new.
Я ведь объявлял их как указатели, так ведь?
Ovl>> m_nNames = new CPString*[99]; Ovl>> for (BYTE i = 0; i < 99; i++) Ovl>> { Ovl>> m_nNames[i] = new CPString(); Ovl>> }
К>// смысл массива указателей — только если ты каждую строчку конструируешь отдельным образом
В смысле?
Ovl>>Первый вопрос: в деструктор при delete m_nTable (и у остальных) для CPString вызовется деструктор или просто указатель в ноль установит?
Ovl>>Или можно вообще этого не делать — vector<>::clear() сам очистит память от всего? К>Он (грубо говоря) выполнит деструкторы указателей. К>А это, фактически, деструктор целого числа. Что там разрушать? К>Поэтому будет куча висячих объектов.
Ovl>>Вызывает ли delete деструктор объекта?
К>Обязательно.
Ovl>>Заранее спасибо
К>Ты случаем не с Паскаля на ++ пересел?
Нет, я настоящий Паскаль вообще с трудом представляю. Просто строки — у меня слабое место. Я привык CString пользовать, ну или если в BCB , то AnsiString. А теперь хочу до конца разобратся. Просто хочется сделать код максимально переносимым.
Здравствуйте, Bell, Вы писали:
B>Для каждого объекта CPString сначала вызывается деструктор, затем овобождается память, который каждый из этих объектов занимал. Кстати для самого CPString я не увидел деструктора. Его нет, или ты его просто не привел?
Не привел.
вот он какой
Кстати, в форуме я видел пример с незакомментированным m_szStr = NULL, но у меня это вызывает ошибку.
Почему?
B>можно и так... B>А еще так: B>В лоб: B>
B>for(vector<CStringTable*>::iterator it = m_vcStrings.begin(), itEnd = m_vcStrings.end(); it != itEnd; ++it )
B> delete *it;
B>
Ovl>Кстати, в форуме я видел пример с незакомментированным m_szStr = NULL, но у меня это вызывает ошибку. Ovl>Почему?
Как справеливо заметил Кодт, у тебя отсутствовали "правильные" конструктор копии и оператор присваивания. Поэтому почти наверняка ошибка была вызвана повторным удалением после (возможно неявного) создания временной копии. Строка m_szStr = NULL не содержит никакого криминала, кроме того, что является совершенно лишней. Впрочем как и проверка if (m_szStr).
B>>
B>>for(vector<CStringTable*>::iterator it = m_vcStrings.begin(), itEnd = m_vcStrings.end(); it != itEnd; ++it )
B>> delete *it;
B>>
Ovl>почему ++it, а не it++?
А в чем разница между префиксной и постфиксной формами operator ++ ?
Здравствуйте, Ovl, Вы писали:
К>>// И вообще, почему не векторы? К>> vector<CPString> m_nNames, m_nMessages; Ovl>Я подумал, что вектор сохдает полную копию объекта и если его (объекта) размер изменяется (а для CPString это в порядке вещей), то это плохо будет. Вектор использует сам объект или только ссылку на него?
Вектор размещает свои данные на куче. Сам sizeof(vector<xxx>) — естественно, величина постоянная.
Упрощенно говоря, вектор — это надстройка над массивом, созданным на куче.
Размер объекта — не изменяется. Это принцип.
Объект может держать указатель на внешнюю память, с которой что-то делает.
Твой CPString, например, держит указатель на массив символов (образующие строчку).
Ovl>>>CStringTable::CStringTable()
Ovl>>>{
Ovl>>> m_nTableName = new CPString();
К>>// члены — не-указатели — не нуждаются в лишнем new. Ovl>Я ведь объявлял их как указатели, так ведь?
Объявлял. Просто — зачем?
Тем более, что sizeof(CPString) == 8, а sizeof(CPString*) = 4. И еще сам объект на куче (от 16 до 64 байт)...
Ovl>>> m_nNames = new CPString*[99];
Ovl>>> for (BYTE i = 0; i < 99; i++)
Ovl>>> {
Ovl>>> m_nNames[i] = new CPString();
Ovl>>> }
К>>// смысл массива указателей — только если ты каждую строчку конструируешь отдельным образом Ovl>В смысле?
В том смысле, что
Object* objects = new Object [100];
// в памяти - последовательность из 100 элементов Object
// были вызваны конструкторы без параметров: Object::Object()
Object** objectptrs = new Object* [100];
for(i = 0; i < 50; ++i)
objectptrs[i] = new Object(taram-param);
for(i = 50; i < 100; ++i)
objectptrs[i] = new Object(shurum-burum);
// каждый объект конструируется индивидуально.
К>>Ты случаем не с Паскаля на ++ пересел? Ovl>Нет, я настоящий Паскаль вообще с трудом представляю. Просто строки — у меня слабое место. Я привык CString пользовать, ну или если в BCB , то AnsiString. А теперь хочу до конца разобратся. Просто хочется сделать код максимально переносимым.
Представь себе, что в твоей CStringTable используются CString
B>>for(vector<CStringTable*>::iterator it = m_vcStrings.begin(), itEnd = m_vcStrings.end(); it != itEnd; ++it )
B>> delete *it;
B>>
Ovl>почему ++it, а не it++?
Потому что ++it экономнее, чем it++.
Условно говоря,
struct the_iterator
{
...
the_iterator& operator++() // ++prefix
{
... // что-то там делаемreturn *this; // возвращаем ссылку на себя (фактически, просто указатель)
}
the_iterator operator++(int) // postix++
{
the_iterator old = *this; // создаем временный объект - старое значение
++(*this); // инкрементируем текущийreturn old; // возвращаем старый (создаем еще одну промежуточную копию)
}
};
B>>>for(vector<CStringTable*>::iterator it = m_vcStrings.begin(), itEnd = m_vcStrings.end(); it != itEnd; ++it )
B>>> delete *it;
B>>>
Ovl>>почему ++it, а не it++?
B>А в чем разница между префиксной и постфиксной формами operator ++ ? B>
в том что при ++it, сначала увеличивается, а потом идет цикл.... наверное...
Здравствуйте, Bell, Вы писали:
B>Ай яй яй B>Итак, когда пишем B>++x; то происходит всего лишь инкремент члена n_. А когда x++, то кроме всего прочего создается временный объект.