Нет никаких причин их использовать.
Класс строк есть в STL, каждый фреймворк содержит свой класс строк.
По эффективности все они работают также, а иногда даже лучше, чем ваш собственный код на C строках.
В любой момент вы их сможете преобразовать к константной строке C.
STl — std::string,std::wstring
VCL — AnsiString,WideString
MFC — CString
Причины для этого такие:
— Вы не забудете освободить объект.
— Вы перестаете думать о переспределении памяти и расчёте необходимого количества памяти.
— Исчезает угроза переполнения буффера.
AnsiString,CString даже содержат в себе sprintf()
Вот такой код:
char q[1024];
strcpy(q, "select p.street from payers as p, pl_accounts as a where a.orgid=");
strcat(q, vOrgID.at(lsOrganisation.GetCurSel()).GetString());
strcat(q, " and p.id=a.payerid group by p.street order by p.street;");
if(!cur.Prepare(q))
Должен выглядеть так:
CString q="select p.street from payers as p, pl_accounts as a where a.orgid=";
q+=vOrgID.at(lsOrganisation.GetCurSel());
q+" and p.id=a.payerid group by p.street order by p.street;";
if(!cur.Prepare(q))
Если if(!cur.Prepare(q)) вдруг не соберётся, то if(!cur.Prepare(q.GetString()))
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Сейчас приходится собеседовать много новичков. ШЕ>Заметил что ничего в жизни не меняется. ШЕ>Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.
ШЕ>Хочу представить такие рекомендации новичкам в C++. Для того чтобы вы могли повысить свой уровень ШЕ>ну и хотя бы лучше пройти собеседование.
ШЕ>Если кто желает что-то добавить — пожалуйста. ШЕ>Только просьба придерживаться таких соглашений:
ШЕ>- Это должны быть грабли, на которые наступают регулярно. ШЕ>- Краткое описание проблемы и методы её решение. ШЕ>- Обяснение причин. ШЕ>- Проверенный (скомпилированный) пример кода.
соседушко по офису, дебил и неряха, десятилетиями пишет код вида:
....
int * arr = new int[some_size];
if (laja)
return;
...
delete [] arr;
Ошибка — тривиальная и дебильная, как и мой сосед: неиспользование РАИИ приводит к тому, что любой ресурс, требующий освобождения (с памятью — это самое простое)
у этого имбецила утекает в любой более/менее сложной функции, где есть какие-то вложенные блоки.
Спасает только статический анализатор, который заваливает этого ЛОШАРУ горами сообщений.
Ес-но, фикся, кретин плодит новое говно и получает по тупой харе от анализатора и т.д. — имя этому процессу — бесконечность.
Of course, the code must be complete enough to compile and link.
Re[2]: Не надо почленно копировать объект, используйте static_cast.
On 09/18/2012 02:46 PM, Шебеко Евгений wrote:
> Часто нужно присвоить потомку содержимое базового класса другого объекта. > Неявный operator=() потомка не работает, когда присваивается базовый класс. > Не надо почленно копировать объект, используйте static_cast.
Евгений, текст правила нужно переформулировать так:
"Никогда не нужно присваивать потомку содержимое базового класса другого
объекта. Если вы вынуждены так делать, то вам нужно пересмотреть дизайн
вашей программы."
Мне ни разу в жизни наверное не пришлость делать такой ужас.
Если же это надо делать, то нужно реализовать в наследнике
конструктор от класса-предка, и там правильно сконструировать
объект и инициализировать недостающие поля.
delete не может вызвать деструктор для тех объектов, чьё объявление классов он не видит.
В таком случае просто освободится память, занимаемая объектом.
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Если класс не содержит явного копирующего конструктора или operator=, то они создаются неявно. ШЕ>Об этом надо помнить.
ШЕ>Допустим у нас есть класс, который содержит в себе указатель на свой буффер.
[тут был код очередного класса буфера]
Для меня new вне конструктора умного указателя (std::shared_ptr, std::unique_ptr или их аналогов из Boost) — признак плохого кода.
В прикладном коде new/delete не нужен, для буфера есть std::vector<char> или его суженный аналог:
Сейчас приходится собеседовать много новичков.
Заметил что ничего в жизни не меняется.
Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.
Хочу представить такие рекомендации новичкам в C++. Для того чтобы вы могли повысить свой уровень
ну и хотя бы лучше пройти собеседование.
Если кто желает что-то добавить — пожалуйста.
Только просьба придерживаться таких соглашений:
— Это должны быть грабли, на которые наступают регулярно.
— Краткое описание проблемы и методы её решение.
— Обяснение причин.
— Проверенный (скомпилированный) пример кода.
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Хочу представить такие рекомендации новичкам в C++.
рекомендую это сделать в блоге: http://rsdn.ru/forum/news/4887194.flat
> Почему-то довольно часто приходится слышать от C++ программистов, что они не > используют стандартную библиотеку. > Согласитесь странно было бы слышать от программиста на JavaScript или PHP: "Я не > использую строки" или "Я не использую массивы или ассоциативные массивы".
О!, Тут можно дооолго и нууудно распинаться. К сож. С++ тут очень сильно
отличается от других языков. Начнём с того, что стандартная библиотека языка С++
появилась много позже языка С++. Также как ни странно стандартная библиотека
языка С++, её дизайн, идёт вразрез со всеми концепциями и парадигмами языка С++,
существовавшими до неё и помимо неё. Т.е. грубо говоря, стандартная библиотека
языка С++ далеко не универсальна, поэтому применимость её достаточно ограничена.
Так что не удивляйтесь, если вам кто-то скажет, что он не применяет STL.
> Зато каждый четвёртый кандидат на должность C++ программиста, никогда не слышал > о STL. > Каждый второй кандидат на предложение отсортировать массив, предлагает > сортировку пузырьком!
Ну, иногда это приемлимо, а иногда это даже лучший способ.
> Только два кандидата, с помощью гугла, смогли дать более-менее рабочий код с > использованием std::sort().
> Между тем основное, что есть в библиотеке это контейнеры и алгоритмы.
алгоритмы вообще может быть не нужны в данном приложении. Там порядка 50
процентов алгоритмов математические и статистические алгоритмы, они далеко не
во всех приложениях используются.
Posted via RSDN NNTP Server 2.1 beta
Re: Не надо почленно копировать объект, используйте static_cast.
Часто нужно присвоить потомку содержимое базового класса другого объекта.
Неявный operator=() потомка не работает, когда присваивается базовый класс.
Не надо почленно копировать объект, используйте static_cast.
#include <stdio.h>
#include <string>
struct human_t
{
std::string first_name;
std::string last_name;
unsigned birth_year;
unsigned birth_month;
unsigned birth_day;
unsigned birth_hour;
unsigned birth_min;
unsigned birth_sec;
human_t()
{
birth_year=birth_month=birth_day=
birth_hour=birth_min=birth_sec=0;
}
};
struct women_t : public human_t
{
std::string maiden_name;
};
int main(int argc,char** argv)
{
human_t h;
women_t w;
//w=h; такая строчка не компилируется
//часто встречается такой код
w.first_name=h.first_name;
w.last_name=h.last_name;
w.birth_year=h.birth_year;
w.birth_month=h.birth_month;
w.birth_day=h.birth_day;
w.birth_hour=h.birth_hour;
w.birth_min=h.birth_min;
w.birth_sec=h.birth_sec;
//можно прощеstatic_cast<human_t&>(w)=h;return 0;
}
> ШЕ>Сейчас приходится собеседовать много новичков. > > Вам слишком рано ещё кого-то собеседовать.
Ребята, вот зачем вот это вот всё ?
В форумах по линуксу линуксоиды сруца, какой дистр лучше.
В форумах по плюсам -- кто плюсы знает лучше ...
Может лучше на неправ(иль|ослав)ные технологии свой гнев обращать
хоть когда-нибудь?
"Пишите так, будто ошибок в программе нет"
Подход призывает правильно пользоваться исключениями и выгодами, которые он предоставляет.
В противовес подхода, когда код ошибки возвращается из функции и обрабатывается с помощью толпы if().
Тема сложная, не берусь комментировать. Лучше почитать в книжке.
это был мой первый вопрос, когда я смотрел его код лет 7 назад. теперь мне очень стыдно, что я это спросил, я
переоценил чувака.
это как, помню, в книге Хэрриота он спросил у реднекоподобных фермеров, как им понравилась последняя пьеса Шоу
кстати, в этом году он все-таки решил использовать вектор — ГАГАГА, ему был нужен динамически растущий массив и, блин,
он быстро сообразил мозгом макаки, что написать это с галимым ручным управлением памятью ему уже БАНАЛЬНО НЕ ПОД СИЛУ.
в итоге все кончилось сломанным билдом не некоторых платформах — про включение заголовка и про пространства имен козел не сообразил.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Сейчас приходится собеседовать много новичков. ШЕ>Заметил что ничего в жизни не меняется. ШЕ>Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.
Зачем все это?
Как уже резонно заметили выше, новички которые это не знают и им это неинтересно — просто ничего не поймут.
Те, кто заинтересовался хорошими С++ практиками — быстро найдут ответы в книгах Саттер/Майерса/Александреску.
Шансы на то, что данный топ прочитают новички — минимален. Так что данный топик разве что вызвать C++ флуд очередной и померяться писюнами.
"Язык С++" "Бьёрн Страуструп" — библия программиста С++
Невероятно удачное описание, удачные примеры как самого языка, библиотеки STL, так и общего подхода к разработке ПО.
"Андрей Александреску: Современное проектирование на С++" — книга скорее вредная, чем полезная.
Она производит сильное впечатление, у читателя сразу случается приступ шаблонизма.
Хотя сам Александреску призывает разумно использовать шаблоны и не заменять ими наследование.
В результате в проекте сразу появляется куча ненужных шаблонов и шаблонных параметров.
Не обошла и меня в свое время эта тенденция.
Такие шаблоны в проекте не нужны:
template<class Loger>
class GsmModem;
template<class Loger>
class GsmModem : public GenericModem<Loger>,public igsm_modem
{
...
};
#define TEMPLATE_INFDEV \
template\
<\
int infdev_id,\
template <class> class CarrierPolicy,\
class CarType,\
template <class> class CarContainerPolicy,\
class DevLogType,\
template <class> class ThreadingPolicy,\
template <class> class PollQueuePolicy,\
template <class> class PollErrorPolicy,\
template <class> class DirReqQueuePolicy,\
template <class> class CustReqQueuePolicy\
>
#define INFDEV infdev<infdev_id,CarrierPolicy,CarType,CarContainerPolicy,DevLogType,ThreadingPolicy,PollQueuePolicy,PollErrorPolicy,DirReqQueuePolicy,CustReqQueuePolicy>
template
<
int infdev_id,
template <class> class CarrierPolicy,
class CarType,
template <class> class CarContainerPolicy=CarContainer,
class DevLogType=DevLog,
template <class> class ThreadingPolicy=SingleThread,
template <class> class PollQueuePolicy=PollQueue,
template <class> class PollErrorPolicy=PollError,
template <class> class DirReqQueuePolicy=DirReqQueue,
template <class> class CustReqQueuePolicy=CustReqQueue
>
class infdev;
Вывод. Книжку читать, она сильно меняет взгляд на понимание С++. Но не надо сразу кидаться воплощать идеи в книжке в своём проекте.
Re[3]: Копирующий конструктор и копирующий operator= по умолчанию.
Здравствуйте, PM, Вы писали:
PM>Для меня new вне конструктора умного указателя (std::shared_ptr, std::unique_ptr или их аналогов из Boost) — признак плохого кода.
Не будь так категоричен, это признак недостатка опыта.
PM>В прикладном коде new/delete не нужен, для буфера есть std::vector<char> или его суженный аналог:
В прикладном — да, но бывает ещё и не-прикладной-код
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Почему-то довольно часто приходится слышать от C++ программистов, что они не используют стандартную библиотеку.
Согласитесь странно было бы слышать от программиста на JavaScript или PHP: "Я не использую строки" или "Я не использую массивы или ассоциативные массивы".
Зато каждый четвёртый кандидат на должность C++ программиста, никогда не слышал о STL.
Каждый второй кандидат на предложение отсортировать массив, предлагает сортировку пузырьком!!!
Только два кандидата, с помощью гугла, смогли дать более-менее рабочий код с использованием std::sort()
Между тем основное, что есть в библиотеке это контейнеры и алгоритмы.
Контейнеры:
std::string — строки
std::vector<> — массив
std::map<> — двоичное дерево или ассоциативный массив
std::set<> — множество. Фактически тот же std::map только хранит одни ключи, без значений.
std::hash_map<>,std::hash_set<> — тоже самое что и std::map<>,std::set<> — только не в бинарном дереве, а в хеш таблице.
Алгоритмы реализуют множество стандартных алгоритмов, знакомых нам с института. Например: поиск, поиск последовательности, двоичный поиск, сортировка, лексикографической сравнение, пересечение\объединение\вычитание множеств, уникалоьность.
Как использовать, на пальцах не объяснишь, придётся почитать книжку. хотя бы Бьёрн Страуструп "Язык C++". Часть "Стандартная библиотека"
Вот тестовое задание, которое вводит в ступор всех кандидатов:
#include <string>
#include <vector>
#include <algorithm>
struct human_t
{
std::string first_name;
std::string last_name;
unsigned age;
human_t()
{
age=0;
}
};
int main(int argc,char** argv)
{
std::vector<human_t> v;
return 0;
}
Отсортировать v по фамилии и имени.
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>По эффективности все они работают также, а иногда даже лучше, чем ваш собственный код на C строках.
эффективности чего?
Вы стали бы писать парсер/генератор который использовал бы std::string ?
On 09/18/2012 02:51 PM, Шебеко Евгений wrote:
> Вот такой код: > > > char q[1024]; > strcpy(q,"select p.street from payers as p, pl_accounts as a where a.orgid="); > strcat(q, vOrgID.at(lsOrganisation.GetCurSel()).GetString()); > strcat(q," and p.id=a.payerid group by p.street order by p.street;"); > if(!cur.Prepare(q)) > > > > Должен выглядеть так:
Ещё очень удобно и правильно использовать вектора для таких временных буферов:
std::vector< char > q(1024);
strcpy(&q[0],"select p.street from payers as p, pl_accounts as a where a.orgid=");
strcat(&q[0], someVal);
strcat(&q[0]," and p.id=a.payerid group by p.street order by p.street;");
Также можно это использовать для временных буферов для вызова C API,
ну и конечно же в даном примере можно подтянуть и boost::printf и многое другое.
В современной версии стандартна так можно использовать и std::string вместо
std::vector.
Только один недостаток: лишняя нагрузка на хип и может быть лишная точка
синхронизации в многопоточных приложениях.
Здравствуйте, MasterZiv, Вы писали:
>> Хотя сам Александреску призывает разумно использовать шаблоны и не заменять ими >> наследование.
MZ>+1. Очень всё правильно.
Что правильно-то? Если нужен статический полиморфизм (времени компиляции), а не динамический (времени выполнения), то как раз нужно использовать шаблоны, а не наследование.
Здравствуйте, Abyx, Вы писали:
ШЕ>>Для динамических объектов можно использовать смарт указатели. Например: shared_ptr (boost::shared_ptr, std::shared_ptr) или std::auto_ptr A>std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr
Вот кстати пример того, почему лучше все-таки читать советы настоящих, а не доморощенных гуру.
Здравствуйте, PlusMyTwitterFace, Вы писали:
PMT>За что минус поясните? Мне не жалко, а действительно интересно.
падение программы на delete — это крайне редкое событие имхо
в моей практике я видел такие последствия:
1) утечка памяти, если массив содержит сложные объекты (из-за того, что не вызовутся деструкторы). при этом память под объекты (не включая их мемберов) будет освобождена
2) никаких проблем, если массив состоит из простых типов или POD-ов
то есть в таком коде на практике нет проблем:
int* x = new int[200];
delete x;
3) никаких проблем, если массив состоит из объектов, которые в деструкторах ничего умного не делают и не освобождают (включая автоматически сгенерированные деструкторы)
мой опят ограничен лишь работой с VS+gcc, возможно, где-то есть более печальные последствия из-за неправильного delete\delete[], но я не слышал о подобных проблемах
AS>>ptrdtor UNIQNAME(...); AS>>typedef std::shared_ptr<void> ptrdtor; P>это как пушкой по воробьям. он же thread-safe ref-count
Э... вопрос то как бы про другое был )
Работает? — Да. RAII? — Тоже да. Просто? — вроде как более чем.
Коротко и понятно без реализации? — ... ну ты же понял.
P>тем более в C++11 можно так
Здравствуйте, wander, Вы писали:
W>Здравствуйте, MasterZiv, Вы писали:
MZ>> Может лучше на неправ(иль|ослав)ные технологии свой гнев обращать MZ>> хоть когда-нибудь?
W>Гнев на технологии лучше тоже не обращать. Технологии надо анализировать и оценивать и, следовательно, применять или не применять по результатам. А гневаться лучше на что-нибудь другое.
А лучше вообще не гневаться, гнев — это грех.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Кодт, Вы писали:
К>Саттерс — это семья Саттеров?
К>Кстати, напоминаю о существовании правил форума, где попрекание собеседников нехваткой квалификации не приветствуется.
Нет, ну "не гуру" это не нехватка квалификации. А то так можно дойти до того, что сказать человеку, что он не гений, будет восприниматься как оскорбление.
Здравствуйте, Abyx, Вы писали:
A>если С++03 — зачем функтор если достаточно функции
насколько я знаю фуктор подставляется в параметр шаблона как тип, то есть чистый compile-time, а функция как указатель на семейство функций со всеми вытекающими.
А как C++98 и C++03 отличаются в этом месте?
А всё потому, что выделенный блок памяти (0x09ac9008) имеет отрицательное смещение от собственно указателя на первый элемент (0x09ac900c). Деструктор первого элемента отрабатывает нормально, а вот собственно освобождение памяти обламывается.
Если вы планируете удалять производный класс, используя указатель на базовый класс, вы должны сделать дестурктор базового класса виртуальным.
Иначе деструктор потомка не будет вызван.
Это также касается случая, когда в вашем производном классе нет явного деструктора. В нём могут быть переменные (например, типа std::string) для которых нужно вызвать деструктор.
Здравствуйте, PM, Вы писали:
PM>[тут был код очередного класса буфера] PM>Для меня new вне конструктора умного указателя (std::shared_ptr, std::unique_ptr или их аналогов из Boost) — признак плохого кода.
для меня new вне make_XXX для умного указателя — грабли. (ещё new легален в своих контейнерах)
используй make_unique, make_shared http://herbsutter.com/gotw/_102/
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Почему-то довольно часто приходится слышать от C++ программистов, что они не используют стандартную библиотеку.
Очень многие при использовании фреймворка стараются использовать только те элементы стандартной библиотеки, которых нет в используемом фреймворке. В результате и получаем "не используют стандартную библиотеку".
ШЕ>Зато каждый четвёртый кандидат на должность C++ программиста, никогда не слышал о STL.
Это прискорбно. С другой стороны, если заниматься буквоедством, и, ЕМНИП, такого слова STL больше нет. Есть просто стандартная библиотека C++, включившая в себя то, что раньше называлось STL (если я не прав -- поправьте).
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Для динамических объектов можно использовать смарт указатели. Например: shared_ptr (boost::shared_ptr, std::shared_ptr) или std::auto_ptr
std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr
ШЕ>Предпочтительнее использовать shared_ptr<>, т.к. внутри него есть счётчик ссылок, что позволяет его безопасно копировать и хранить в контейнерах.
ниразу не предпочтительнее. он потокобезопасный и потому очень медленный, так что предпочтительнее — std::unique_ptr.
к томуже в большинстве случаев общее владение объектом не нужно.
> Вопрос-то не в том, а в том, зачем нужны советы от Шебеко.
ПО-моему так всё очень правильно и здорово. Не важно, от кого советы, важно,
чтобы были правильные. А еси повторяются -- не страшно, лишний раз кто-то
прочитает -- хуже не будет.
Здравствуйте, MasterZiv, Вы писали:
MZ>ПО-моему так всё очень правильно и здорово. Не важно, от кого советы, важно, MZ>чтобы были правильные. А еси повторяются -- не страшно, лишний раз кто-то MZ>прочитает -- хуже не будет.
Да нет, просто в книге все собрано и ссылки на Мейерса, Саттера, Страуструпа и других, если кого какая тема заинтересовала и хочется поподробнее. И книга сама тонюсенькая, чуть больше 200 страниц.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>ой, я не заметил, что ты уже писал про такое. но, короче, когда человек пишет в стиле "назад в 1982 к С с классами" — это его ежедневный "паттерн" — неспособность освободить ресурсы.
Здравствуйте, Abyx, Вы писали:
A>>>если С++03 — зачем функтор если достаточно функции P>>насколько я знаю фуктор подставляется в параметр шаблона как тип, то есть чистый compile-time, а функция как указатель на семейство функций со всеми вытекающими. A>да, в каких-то версиях MSVC именно так (хз как в MSVC11), а в g++ вроде функция инлайнится, IIRC
функция конечно может инлайнится — и она скорей всего нормально инлайнится во многих версиях msvc, и gcc, но у функтора намного больше шансов.
написать лишние двадцать буковок для функтора — не проблема, большой смысловой нагрузки они не несут, ошибится в них трудно
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Сейчас приходится собеседовать много новичков. ШЕ>Заметил что ничего в жизни не меняется. ШЕ>Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.
ШЕ>Хочу представить такие рекомендации новичкам в C++. Для того чтобы вы могли повысить свой уровень ШЕ>ну и хотя бы лучше пройти собеседование.
ШЕ>Если кто желает что-то добавить — пожалуйста. ШЕ>Только просьба придерживаться таких соглашений:
ШЕ>- Это должны быть грабли, на которые наступают регулярно. ШЕ>- Краткое описание проблемы и методы её решение. ШЕ>- Обяснение причин. ШЕ>- Проверенный (скомпилированный) пример кода.
Я было начал отвечать на ваши сообщения, но потом понял, что пересказываю содержание книг Майерса и Саттера. Новичкам это бесполезно — они еще не наступили на все грабли, опытным С++ программистам это уже 10 лет как не интересно.
Так что новичкам я бы порекомендовал читать умные книги и писать реальный код
Шебеко Евгений:
ШЕ>Если класс не содержит явного копирующего конструктора или operator=, то они создаются неявно. ШЕ>Об этом надо помнить.
.... ШЕ>Решение — сделать private копирующий конструктор и operator=. При этом достаточно их просто объявить, тело функций добавлять не надо.
C++11 пока, наверное, мало востребован, но, давая общие рекомендации по C++, совсем его игнорировать не стоит. В данном случае можно явно объявить копирующие функции как deleted, либо, что ещё лучше, добавить в класс пользовательский конструктор перемещения и (опционально) перемещающий оператор присваивания (неявно объявленные копирующие конструктор и оператор присваивания при этом автоматом будут считаться deleted, хотя для некоторых недоразвитых компиляторов =delete всё же придётся прописывать вручную).
Re[2]: Не надо почленно копировать объект, используйте static_cast.
L_L>>это был мой первый вопрос, когда я смотрел его код лет 7 назад. теперь мне очень стыдно, что я это спросил, я L_L>>переоценил чувака.
K>Да вообще всякое бывает. Может такое было оправдано? Хотя в 99% проще заюзать стл.
В коде, который они лобали в 95-ом 96-ом — воплне возможно. Плохо, что с тех пор С++ для них таким, как он был в начале девяностых
K>Странно, что был выбран вектор для этого.
Вектор ему лучше всего подошел.
K>Зато он наверное все собеседования прошёл.
в этом году было какое-то подобие аттестации для сотрудников типа него (у него очень хорошая позиция-контракт, он практически бессмертен) — он прибежал с нее, подпрыгивая от радости,
из чего я сделал вывод, что все зашибись и удачно прошло.
Of course, the code must be complete enough to compile and link.
Здравствуйте, kov_serg, Вы писали:
_>В конструкторе всегда таблица от текущего класса и в деструкторе тоже. _>Именно эта особенность приводит к граблям при параллельном исполнении.
На самом деле, грабли там в кривом дизайне и перекрытии времени жизни.
Ну нельзя делать так, что время жизни объекта-работодателя (до входа в деструктор) было короче, чем время жизни потока-подчинённого.
А если очень-очень хочется задействовать RAII, чтобы поток гасился из деструктора, — так не надо смешивать объект-работодатель и RAII-сторож.
Да, получится двухфазная деинициализация.
И вообще, ООП конкретно в этом месте больше мешает, чем помогает, — провоцируя на антипаттерн самоубийцы. ФП-подход, где данные для потока передаются в замыкание и там живут до самой смерти, — более естественнен.
Перекуём баги на фичи!
Re: Копирующий конструктор и копирующий operator= по умолчанию.
Легко ошибиться и выполнить присваивание или вызвать копирующий конструктор для такого объекта.
Вот такой код запросто скомпилируется и будет работать неправильно.
Т.е. мы присвоили указатель data объекта a объектам b и c.
В результате у нас 3 раза освободился один и тот же указатель, а data объекта c вообще потерялся.
Решение — сделать private копирующий конструктор и operator=. При этом достаточно их просто объявить, тело функций добавлять не надо.
Если вы создаёте объект, то для его разрушения должны вызывать delete.
Если вы создаёте массив, то для его разрушения должны вызывать delete[].
Иначе ваш код будет работать неправильно.
Для компилятора указатель на объект и указатель на массив неразличимы, поэтому это ваша проблема следить, какой delete вызвать.
item_t* v= new item_t;
...
delete v;
item_t* v= new item_t[100];
...
delete[] v;
Что будет, если для массивов вызвать обычный delete?
Либо осовободится только один объект, либо программа упадёт.
Можете сами в этом убедится, выполнив такой код:
Старайтесь избегать в коде явного освобождения ресурсов.
Причины для этого такие:
— Вы можете выйти из области видимости (например, return посреди функции), забыв освободить ресурс.
— В функции или в вызываемых функциях может произойти исключение.
Поэтому либо ресурс останется неосвобождённым, либо придётся расставлять try\catch после каждой инициализации ресурсов в функции.
//Пример автоматического вызова fclose()class file_hldr
{
file_hldr(const file_hldr&);
void operator=(const file_hldr&);
public:
FILE* f;
file_hldr(FILE* _f) {f=_f;}
~file_hldr(){if(f)fclose(f);}
};
//Использовать так:void foo()
{
FILE* f=fopen("data.txt","rb");
file_hldr fh(f);//С этого момента, чтобы не случилось для f будет вызван fclose()
...
}
Для динамических объектов можно использовать смарт указатели. Например: shared_ptr (boost::shared_ptr, std::shared_ptr) или std::auto_ptr
Предпочтительнее использовать shared_ptr<>, т.к. внутри него есть счётчик ссылок, что позволяет его безопасно копировать и хранить в контейнерах.
Для строк std::string или тот класс строк, который использует ваш фреймворк. CString, например.
Для массивов, с некоторыми оговорками, можно использовать std::vector<>. Даже в том случае, когда нужно получить прямой указатель на массив объектов.
Для остальных ресурсов, часто фреймворк, который вы используете, уже предоставляет классы-обёртки. Поищите их и пользуйтесь. Например, CFile,CPen,CBrush, CDC и т.д.
Для ваших собственных ресурсов вполне можно написать такую же поделку, как я привёл выше.
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Нет никаких причин их использовать.
Вообще-то нет никакого разумного способа обойтись без их использования. Ибо любой фреймворочный класс строк инициализируется из C-строки. Ну это так, 5 коп.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
On 09/18/2012 02:56 PM, Шебеко Евгений wrote:
> "Андрей Александреску: Современное проектирование на С++" — книга скорее > вредная, чем полезная. > Она производит сильное впечатление, у читателя сразу случается приступ шаблонизма. > Хотя сам Александреску призывает разумно использовать шаблоны и не заменять ими > наследование.
ой, я не заметил, что ты уже писал про такое. но, короче, когда человек пишет в стиле "назад в 1982 к С с классами" — это его ежедневный "паттерн" — неспособность освободить ресурсы.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Каждый второй кандидат на предложение отсортировать массив, предлагает сортировку пузырьком!!! ШЕ>Только два кандидата, с помощью гугла, смогли дать более-менее рабочий код с использованием std::sort()
А я знаю сортировку выбором!
Если бы мне предложили отсортировать контейнер, то я специально использовал бы сортировку выбором с использованием станалртных алгоритмов!
ШЕ>Вот тестовое задание, которое вводит в ступор всех кандидатов:
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>>std::hash_map<>,std::hash_set<>
A>нету таких классов в std
ШЕ>>//предикат ШЕ>>struct human_pr ШЕ>>{ ШЕ>> inline bool operator()(const human_t& a,const human_t& b) const ШЕ>> { ШЕ>> if(a.last_name!=b.last_name)return a.last_name<b.last_name; ШЕ>> return a.first_name<b.first_name; ШЕ>> } ШЕ>>}; ШЕ>>
A>если С++03 — зачем функтор если достаточно функции A>если С++ — должна быть лямбда.
К функции вы не сможете применить адаптеры, как, например, std::not1.
Лямбда выражения целесообразно применять, лишь когда они используется в какой-то локальной области кода. Если же они захватывают локальные переменные, а ич функциональность должна использоваться в нескольких местах кода и единиц трансляции, то лучше использовать функциональные объекты.
Здравствуйте, Piko, Вы писали:
A>>если С++03 — зачем функтор если достаточно функции
P>насколько я знаю фуктор подставляется в параметр шаблона как тип, то есть чистый compile-time, а функция как указатель на семейство функций со всеми вытекающими.
да, в каких-то версиях MSVC именно так (хз как в MSVC11), а в g++ вроде функция инлайнится, IIRC
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>странно, что ты не понял — я не об особенностях определенной реализации С++ говорю, а о том, что люди на С++ пишут, как будто у них С или что похуже.
Мне в самом деле стало интересно, с самого ли начала в C++ или C с классами был деструктор.
А вот по поводу "как будто у них С" несогласен. На C, когда в функции выделяются русурсы, return как правило один — в конце. (Или его вообще нет, если функция ничего не возвращает.)
Здравствуйте, Сыроежка, Вы писали:
A>>если С++03 — зачем функтор если достаточно функции A>>если С++ — должна быть лямбда. С>К функции вы не сможете применить адаптеры, как, например, std::not1.
1. есть std::ptr_fun.
2. к human_pr not1 не применишь, во-первых он бинарный, во-вторых он не определяет argument_type.
3. нафига not1 в данной конкретной задаче?
С>Лямбда выражения целесообразно применять, лишь когда они используется в какой-то локальной области кода. Если же они захватывают локальные переменные, а ич функциональность должна использоваться в нескольких местах кода и единиц трансляции, то лучше использовать функциональные объекты.
Я удивлён, но мысль у тебя верная, браво!
Вот только к обсуждаемому примеру не относится, там лямбду использовать целесообразно
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>каждый четвёртый кандидат на должность C++ программиста, никогда не слышал о STL.
Странно. А выборка у Вас большая?
Возможно, это связано с тем, что не везде, где используется С++ получается использовать STL.
Или не используют именно по религиозным соображениям?
Здравствуйте, Abyx, Вы писали:
A>если С++03 — зачем функтор если достаточно функции
1) Если используются биндеры или адаптеры
2) Функтор умеет хранить значения, что иногда удобно. Например for_each возвращает объект переданный в качестве функции. Правда тут нужно быть осторожным, точно быть уверенным в том, что передаваесый объект не копируется внутри алгоритма.
3) Часто это более эфективно т.к. вызов можно сделать встраеваемым
Здравствуйте, ML380, Вы писали:
ML>Здравствуйте, Abyx, Вы писали:
A>>если С++03 — зачем функтор если достаточно функции
ML>1) Если используются биндеры или адаптеры ML>2) Функтор умеет хранить значения, что иногда удобно. Например for_each возвращает объект переданный в качестве функции. Правда тут нужно быть осторожным, точно быть уверенным в том, что передаваесый объект не копируется внутри алгоритма.
не надо вырезать код из моего поста.
зачем в *том* коде функтор?
ML>3) Часто это более эфективно т.к. вызов можно сделать встраеваемым
зависит от компилятора.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>>странно, что ты не понял — я не об особенностях определенной реализации С++ говорю, а о том, что люди на С++ пишут, как будто у них С или что похуже.
I>Мне в самом деле стало интересно, с самого ли начала в C++ или C с классами был деструктор.
I>А вот по поводу "как будто у них С" несогласен. На C, когда в функции выделяются русурсы, return как правило один — в конце. (Или его вообще нет, если функция ничего не возвращает.)
ну вот у удода — какой-то гибрид из С и С++, который можно назвать условно С с классами: вроде классы есть, а ничего больше от С++ он и не позаимствовал,
ресурсы освобождает вручную, как в С, а техники С с одним местом выхода — он и не знал никогда. недо С, недо С++, высер.
Of course, the code must be complete enough to compile and link.
> Что правильно-то? Если нужен статический полиморфизм (времени компиляции), а не > динамический (времени выполнения), то как раз нужно использовать шаблоны, а не > наследование.
18.09.2012 13:44, Шебеко Евгений пишет:
> Если вы создаёте объект, то для его разрушения должны вызывать delete. > Если вы создаёте массив, то для его разрушения должны вызывать delete[]. > > item_t* v=new item_t; > ... > delete v; > > item_t* v=new item_t[100]; > ... > delete[] v;
Опять же, лучше использовать какой контейнер или *_ptr какой.
18.09.2012 13:52, Шебеко Евгений пишет:
> Почему-то довольно часто приходится слышать от C++ программистов, что > они не используют стандартную библиотеку.
Потому что здесь количество велосипедопесателей зашкаливает в отличие от
JavaScript или PHP.
> Зато каждый четвёртый кандидат на должность C++ программиста, никогда не > слышал о STL.
Зато они могут написать сходу различные виду сортировки небось.
> Каждый второй кандидат на предложение отсортировать массив, предлагает > сортировку пузырьком!!! > Только два кандидата, с помощью гугла, смогли дать более-менее рабочий > код с использованием std::sort()
Потому что куча клоунов на собеседованиях именно просят реализовать
сортировку (об этом тут было море срачей) и очень обижаются, если им
предлагают библиотечный sort.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>соседушко по офису, дебил и неряха, десятилетиями пишет код вида: L_L>Спасает только статический анализатор, который заваливает этого ЛОШАРУ горами сообщений. L_L>Ес-но, фикся, кретин плодит новое говно и получает по тупой харе от анализатора и т.д. — имя этому процессу — бесконечность.
А куда смотрит тимлид и прочий менеджмент?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
ШЕ>void foo()
ШЕ>{
ШЕ> FILE* f=fopen("data.txt","rb");
ШЕ> file_hldr fh(f);//С этого момента, чтобы не случилось для f будет вызван fclose()
ШЕ> ...
ШЕ>}
ШЕ>
Разве это пример RAII?
Вот если бы Ваш file_hldr сам открывал файл...
ШЕ>>void foo()
ШЕ>>{
ШЕ>> FILE* f=fopen("data.txt","rb");
ШЕ>> file_hldr fh(f);//С этого момента, чтобы не случилось для f будет вызван fclose()
ШЕ>> ...
ШЕ>>}
ШЕ>>
VF>Разве это пример RAII? VF>Вот если бы Ваш file_hldr сам открывал файл...
То есть я так понимаю такой код ни есть RAII:
int main() {
FILE *f; ptrdtor UNIQNAME( f = fopen("1.c","r"), call_ifn0(fclose) );
printf("file: %p",f);
//...
}
ну, судя по использованию:
ptrdtor — что-то типа scoped_ptr, но хранящий "deleter"
UNIQNAME — макрос раскрывающийся в типа уникальный идентификатор.
call_ifn0 — унарный функтор, сравнивающий в operator() аргумент на 0, и если не ноль то вызывает функтор переданный в конструкторе с этим аргументом.
Здравствуйте, Alexéy Sudachén, Вы писали:
AS>Э... вопрос то как бы про другое был )
не спорю
P>>тем более в C++11 можно так AS>Ну, классно да. Десятая студия прожуёт? )
десятая давится, одиннадцатая — давится, gcc-4.5.1 — жуёт.
с одиннадцатой вообще прикол, она на fclose выдаёт, ошибку компиляции, по дефолту! всё, приплыли
Error 1 error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
в любом случае, для чего там локальная переменная, а не просто return? или это без смысловой нагрузки?
P>в любом случае, для чего там локальная переменная, а не просто return? или это без смысловой нагрузки?
Ну вообще-то простейший способ вернуть структуру, совместимый со всем что движется. Можно конечно конструктор написать ... но зачем? Код в результате всё равно один и тот же будет — записать в rax указатель и выйти из функции. Хотя итоге оно таки заинлайнится и выродится в передачу результата fopen и адреса fclose в конструктор.
Здравствуйте, Alexéy Sudachén, Вы писали:
AS>Ну вообще-то простейший способ вернуть структуру, совместимый со всем что движется. Можно конечно конструктор написать ... но зачем? Код в результате всё равно один и тот же будет — записать в rax указатель и выйти из функции. Хотя итоге оно таки заинлайнится и выродится в передачу результата fopen и адреса fclose в конструктор.
может в этом конкретном случае и заинлайнится. но, вот тот же msvc nrvo не делает в debug, а rvo делает.
да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно..
P>может в этом конкретном случае и заинлайнится. но, вот тот же msvc nrvo не делает в debug, а rvo делает.
Какая разница? Это просто указатель. Мало ли как он представлен и во что завёрнут.
P>да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно..
Э... покажи мне сгенерированный код, возвращающий указатель без использования rax.
Здравствуйте, Alexéy Sudachén, Вы писали:
P>>да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно.. AS>Э... покажи мне сгенерированный код, возвращающий указатель без использования rax.
при rvo/nrvo в функцию передаётся скрытая ссылка, на то, куда писать результат. я предполагал, что в этом случае eax не заполняется. но видимо так оптимальней — чтобы лишний раз не высчитывать.
P>при rvo/nrvo в функцию передаётся скрытая ссылка, на то, куда писать результат. я предполагал, что в этом случае eax не заполняется. но видимо так оптимальней — чтобы лишний раз не высчитывать. P>то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности.
Таки получается что чутьё меня не подвело, а CL откровенно тупит. Получается что я был о нём лучшего мнения. Ну и нафиг нужен такой RVO?
#include <stdio.h>
struct A {
void *f;
void operator()() { printf("%p\n",f); }
};
A __declspec(noinline) g(void *p) {
A a = { p };
return a;
}
struct B {
void *f;
B(void *ff) : f(ff) {}
void operator()() { printf("%p\n",f); }
};
B __declspec(noinline) gg(void *p) {
return B(p);
}
int main()
{
A a = g((void*)1);
B b = gg((void*)2);
a();
b();
}
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Если класс не содержит явного копирующего конструктора или operator=, то они создаются неявно. ШЕ>Об этом надо помнить.
Каноническая формулировка называется Law of the Big Three: «если в вашем классе понадобилось явно определить деструктор, копирующий конструктор или оператор присваивания, скорее всего вам нужны все три».
Здравствуйте, MasterZiv, Вы писали:
MZ>Ребята, вот зачем вот это вот всё ? MZ>В форумах по линуксу линуксоиды сруца, какой дистр лучше. MZ>В форумах по плюсам -- кто плюсы знает лучше ...
Чтобы узнать новое. В данном случае у топикстартера есть шанс понять, что он (пока еще) не гуру. Продолжать пописывать советы конечно можно, но рекомендовать их "собеседуемым" не стоит, тем более, что в природе существуют аналогичные советы мирового уровня.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Abyx, Вы писали:
ШЕ>>>Для динамических объектов можно использовать смарт указатели. Например: shared_ptr (boost::shared_ptr, std::shared_ptr) или std::auto_ptr A>>std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr
I>Вот кстати пример того, почему лучше все-таки читать советы настоящих, а не доморощенных гуру.
Здравствуйте, MasterZiv, Вы писали:
MZ> Может лучше на неправ(иль|ослав)ные технологии свой гнев обращать MZ> хоть когда-нибудь?
Гнев на технологии лучше тоже не обращать. Технологии надо анализировать и оценивать и, следовательно, применять или не применять по результатам. А гневаться лучше на что-нибудь другое.
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>delete не может вызвать деструктор для тех объектов, чьё объявление классов он не видит.
ну об этом и компилятор прожужжит если что:
function 'int main(int, char**)':
warning: possible problem detected in invocation of delete operator:
warning: 'v' has incomplete type
warning: forward declaration of 'struct human_t'
note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
ну или так:
warning C4150: deletion of pointer to incomplete type 'human_t'; no destructor called
see declaration of 'human_t'
Здравствуйте, Abyx, Вы писали:
A>std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr
Согласен, но на практике вынужден использовать std::auto_ptr из-за Boost.PointerContainer, который я обычно использую в любом проекте.
Почему то разработчики PointerContainer не удосужились сделать методы с тем же boost::scoped_ptr, поэтому приходится делать так:
Здравствуйте, savitar, Вы писали:
A>>std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr
S>Согласен, но на практике вынужден использовать std::auto_ptr из-за Boost.PointerContainer, который я обычно использую в любом проекте. S>Если бы хотябы у boost::scoped_ptr был метод release(), но его нет, интересно почему?
есть секретный класс <boost/interprocess/smart_ptr/unique_ptr.hpp>
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Сейчас приходится собеседовать много новичков. ШЕ>Заметил что ничего в жизни не меняется. ШЕ>Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.
ШЕ>Хочу представить такие рекомендации новичкам в C++. Для того чтобы вы могли повысить свой уровень ШЕ>ну и хотя бы лучше пройти собеседование.
Для новичков все эти советы не работают, пока они сами не наступят на все эти грабли.
Здесь выбор только один из двух: — не брать новичков; — смириться (если есть дополнительные деньги и время на рефакторинг и обучение)
Здравствуйте, Alexéy Sudachén, Вы писали:
P>>при rvo/nrvo в функцию передаётся скрытая ссылка, на то, куда писать результат. я предполагал, что в этом случае eax не заполняется. но видимо так оптимальней — чтобы лишний раз не высчитывать. P>>то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности. AS>Таки получается что чутьё меня не подвело, а CL откровенно тупит. Получается что я был о нём лучшего мнения. Ну и нафиг нужен такой RVO?
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>>соседушко по офису, дебил и неряха, десятилетиями пишет код вида: L_L>>Спасает только статический анализатор, который заваливает этого ЛОШАРУ горами сообщений. L_L>>Ес-но, фикся, кретин плодит новое говно и получает по тупой харе от анализатора и т.д. — имя этому процессу — бесконечность.
CC>А куда смотрит тимлид и прочий менеджмент?
видимо, пофигу. то ли тут действует правило: "чел старый и проверенный" (он у истоков), то ли еще проще: ковыряться в высерах этого "творца" никому не охота, пусть он сам и сидит годами на этом дерьме.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
K>>Почему он вектор не использует?
L_L>это был мой первый вопрос, когда я смотрел его код лет 7 назад. теперь мне очень стыдно, что я это спросил, я L_L>переоценил чувака.
Да вообще всякое бывает. Может такое было оправдано? Хотя в 99% проще заюзать стл.
L_L>кстати, в этом году он все-таки решил использовать вектор — ГАГАГА, ему был нужен динамически растущий массив и, блин,
Странно, что был выбран вектор для этого. L_L>он быстро сообразил мозгом макаки, что написать это с галимым ручным управлением памятью ему уже БАНАЛЬНО НЕ ПОД СИЛУ. L_L>в итоге все кончилось сломанным билдом не некоторых платформах — про включение заголовка и про пространства имен козел не сообразил.
Зато он наверное все собеседования прошёл.
Здравствуйте, Kernan, Вы писали:
L_L>>кстати, в этом году он все-таки решил использовать вектор — ГАГАГА, ему был нужен динамически растущий массив и, блин, K>Странно, что был выбран вектор для этого.
а что не так? vector — он как-бы дефолт, и не плохой дефолт. и даже в стандарте написанно, что он дефолт.
хочется deque? нужно сначала обосновать
Я вот чего понять не могу, ты прикалываешься или серьёзно не знаешь что на x86 C/C++ оптимально возвращают объекты размером до 2 слов процессора через регистры? Очевидно, что студия откровенно тупит, не оптимизируя такой кейc с RVO. Ещё более она тупит при возврате структуры размером больше двух слов, чего гнусь не делает. Что меня удивило, да. Гнусь возвращает такие структуры совершенно одинаково для обоих случаев.
То есть мой способ, там где он использован, заведомо не хуже чем любой другой. Так что не надо придумывать новую задачу и говорить что в ней то всё не так. Это уже будет другая задача.
Здравствуйте, Alexéy Sudachén, Вы писали:
P>>а знаешь что ему голову сносит? Аггрегаты! AS>Я вот чего понять не могу, ты прикалываешься или серьёзно не знаешь что на x86 C/C++ оптимально возвращают объекты размером до 2 слов процессора через регистры?
ээ, я пример привёл — там точно больше двух слов
AS>Очевидно, что студия откровенно тупит, не оптимизируя такой кейc с RVO.
там NRVO.
RVO она даже в debug делает
AS>То есть мой способ, там где он использован, заведомо не хуже чем любой другой. Так что не надо придумывать новую задачу и говорить что в ней то всё не так. Это уже будет другая задача.
да не, естественно в том примере это вообще не важно, точно также как shared_ptr — это обсудили вроде?
я в общем показываю, что RVO предпочтительней...
Здравствуйте, kov_serg, Вы писали:
_>Деструкторы записывают обратно свою таблицу виртуальных функций.
не важно кто что и куда записывает, вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные, самый простой способ не наступать на грабли: "не делайте так" (используйте двухфазную инициализацию/удаление).
Здравствуйте, XuMuK, Вы писали:
XMK>Здравствуйте, kov_serg, Вы писали:
_>>Деструкторы записывают обратно свою таблицу виртуальных функций.
XMK>не важно кто что и куда записывает, вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные, самый простой способ не наступать на грабли: "не делайте так" (используйте двухфазную инициализацию/удаление).
Ептить. Я же не говорю что это правильно. Я говорю что это неявная грабля на которую можно наступить. И она заложена в дизайне VCL и MFC.
Здравствуйте, Masterkent, Вы писали:
M>XuMuK:
XMK>>вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные
M>Вызовы там виртуальные, только final overriders определяются специфически.
M>
Здравствуйте, XuMuK, Вы писали:
_>>Деструкторы записывают обратно свою таблицу виртуальных функций.
XMK>не важно кто что и куда записывает, вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные,
Функции там вызываются как виртуальные — но только для текущего типа, т.е. для базы.
Насколько компилятору хватает поля зрения, он подменяет виртуальный вызов статическим.
struct base
{
virtual void f() {}
void g() { f(); } // здесь будет заведомо виртуальный вызов (хотя, компилятор может проинлайнить g()...)
base() { f(); g(); } // по крайней мере единожды будет виртуальный вызов f() - из g()
};
XMK> самый простой способ не наступать на грабли: "не делайте так" (используйте двухфазную инициализацию/удаление).
"Не делайте так" здесь значит более общее: не лезьте в разрушаемый объект, особенно — из другого потока, особенно — оставаясь в функции-члене разрушаемого объекта (впрочем, есть способ отстрелить себе ногу и в однопоточном режиме и даже без виртуальных функций).
Не всплывёт его бедное тело, грабли на дне я поставил умело.
Антипаттерн "самоубийца" зашит в библиотеку C'est la vie. (Et la MORT!!!)
Имхо, лучшее, что можно сделать здесь — это использовать TThread/CWinThread исключительно как хэндл потока, и никогда от них не наследоваться.
Не приходит же в голову (или приходит? после стольких лет с дебилдером и мфц?) наследоваться от boost/std::thread ?