Минусуют за то, что не различаете компилятор и IDE.
И это, в CodeBlocks используется GCC. А значит сам редактор тут не при чем.
PS. я минусов не ставил.
1) Это да. Передача через event`ы эту проблему решает.
2) Я не считаю это проблемой, все равно интерфейс, определенный в MyThread будет привязан к конкретной задаче. Класс на практике называться будет соответственно этой задаче (а не MyThread). С другой стороны этот способ точно так же довольно просто поддаётся шаблонизации. Поэтому, если уже очень хочется, можно придумать нечто обобщённое на этой базе.
К слову сказать с более ранних версиях Qt event based межпоточное взаимодействие было основным способом. Т.к. во-первых поток не имел своей встроенной очереди сообщений, как в Qt4-Qt5, а во-вторых система сигналов не поддерживала межпоточные соединения. Приходилось делать свою очередь сообщений внутри run и проектировать систему событий для потока. Зато можно было передавать в основной поток события с помощью функции postEvent (собственно сейчас так тоже можно).
В журнале DrDobbs помню статью (к сожалению ссылку найти не могу), в которой показывались приемы работы с многопоточностью в Qt.
Одна из концепций такова (демонстрационный пример):
class MyThreadImpl
: public QObject
{
Q_OBJECT
public:
MyThreadImpl();
public slots:
void doStuff()
{
// impl...
emit onSomeStuff();
// impl
}
signals:
void onSomeStuff();
};
class MyThread
: public QThread
{
Q_OBJECT
public:
void doStuff()
{
emit doStuffImpl();
}
signals:
// external
void onSomeStuff();
// internal
void onStuffImpl();
private:
void run()
{
MyThreadImpl threadImpl;
// signal to thread
connect(this, SIGNAL(onStuffImpl()), &threadImpl, SLOT(doStuff()));
// signal from thread
connect(&threadImpl, SIGNAL(onSomeStuff()), this, SIGNAL(onSomeStuff()));
exec();
}
};
Со своей стороны нахожу данный подход одним из самых удачных для Qt и всем его рекомендую. Функции типа moveToThread считаю костылями, призванными исправлять существующие архитектурные косяки в проекте. Использовать их для новых решений ИМХО не стоит.
Аналогичный, более классический пример с использованием QEvent, который несколько более многословен, однако дает лучшую производительность.
while и for помимо своей цикличности вносят еще и область видимости. Это особенно важно для С++. Поэтому если и использовать goto, то с фигурными скобками:
int main ()
{
loop:
{
printf("1\n");
}
goto loop;
}
Получается даже немного длинее. Нет, все-таки в этом случае право большинство: for и while — лучше.
Хрень говорил. Геморрой — суть болезнь от плохого кровообращения. То есть сидишь ты весь день на заднице, застой крови образуется — как следствие — геморрой. У велосипедистов такого быть не может — ибо мышцы ягодичные всегда в тонусе. Да и массаж от седла неплохой.
Как раз таки не через Си-код. А в обход его. Задача во-первых не допустить попадания в Си-код исключений и нарушения контракта. Во-вторых оставить для пользователя библиотеки возможность их генерировать (в моем случае неизбежно, потому что код уже написан).
Смысл «протаскивания» в том, что обработка исключения должна быть в том месте, где это нужно. Если переносить всю обработку в код враппера — это будет прямое нарушение инкапсуляции. Враппер просто не может знать об особенностях клиентского кода.
Ну так а я не говорю про С. Я говорю для С++, почему бы не прочитать вопрос habrahabr.ru/blogs/cpp/100623/#comment_3113697, прежде чем дискуссию начинать? :) Я объяснял, что код который вызывается из Си не защищен от С++-исключений. В случае callback`ов в Си библиотеках, это тоже самое, что если бы код на Си вызывал С++ код.
Причем я как раз отметил чем это чревато и почему нельзя такого допускать.
В чем идея? Есть либина XML, к ней есть С++ враппер. С++ враппер С++ библиотека? Да. Почему бы не использовать вместе с ней исключения. Однако в недрах враппера юзаются коллбэки, который выполняются в Си коде. Потому что враппер — над С-XML-либиной. Так как разрешить проблему? СС одной стороны как бы юзер враппера не виноват, он же юзает С++, с другой стороны ему вдруг нельзя использовать исключения. Это решение этой проблемы.
Да, основная идея в том, чтобы код, который использует MyLib не вынуждать отказываться от исключений. Чтобы этот код претерпел как можно меньше изменений. Для этого надо их где-то запомнить, а прежде чем запомнить, надо их отфильтровать.
Шаблоны — для удобстве фильтрации. Если в mylib не один callback, а 10, и в каждом callback`е написано нечто вроде: try
{
this_->callback();
}
catch(exception1)
{
}
catch(exceptionN)
{
}
Особенно если нужно добавить новое исключение, все это превращается в жуткую кашу. А у меня достаточно в одном месте дописать нужный тип в список исключений.
> Я не зря привел в пример expat. Проблема исключений встала именно при использовании этой
> библиотеки. Задача состояла в следующем:
> * Есть некий код, который раньше использовал библиотеку xml, написанную на С++ и этот код
> активно применял исключения;
> * Есть необходимость заменить библиотеку xml на другую без переписывания остального кода.
В данном контексте с ним все в порядке. Я сам передал указатель this, скастив его к void*, сам его же и забрал и скастил обратно. pureCLibSetUserData(this);
Так он и не знает. В этом и проблема. И при исключении функция не возращает никакого результата. Она прерывается альтернативно с раскруткой стека. Как это реализовано конкретно — зависит от компилятора.
> А зачем бросила?
Предлагается решение, при котором такого вопроса бы не возникало. Исключение не должно покидать пределы С++.
> Предлагается костыль для кривых библиотек?
В C++ исключения — это нормальное явление, new кидает исключение, dynamic_cast кидает искючения, STL кидает исключения. Кривизна библиотеки будет только тогда, когда она позволит исключению попасть в чужую среду.
Ну, давайте немного упростим ситуацию. Представьте, что вы пишете на языке Си и подключаете к проекту библиотеку написанную на С++. Библиотека эта, предположим, экспортирует функции, помеченные как extern «C», то есть такие функции свободно можно из Си вызывать. Так вот. Теперь представьте, что одна из таких функций бросила исключение. Куда оно попадет? И какие в Си есть возможности для его перехвата?
Пример на Си: void foo(int (*callback)(char *))
{
char * buffer;
int ret;
buffer = malloc(100000);
ret = callback(buffer);
free(buffer);
}
Если сallback — это функция из С++, то она может бросить исключение. При этом будет утечка памяти, так как buffer не будет освобожден.
Конечно, без крайней необходимости прибегать к такому я бы тоже не стал. Если проектировать систему с нуля, то такие вещи нужно прогнозировать. Однако у меня был уже готовый проект, который нужно было портировать на платформу, где QtXML (именно она и есть та С++ xml-библиотека) не существовало в природе, а был только expat.
— Совковая лопата говно, я весь участок штыковой перекопал, очень удобно! 5 лет до этого копал совковой, ну и извращенцы же ее придумали!
Заканчивайте с этим, короче. Эмоции в инженерии — лишнее дело.
И это, в CodeBlocks используется GCC. А значит сам редактор тут не при чем.
PS. я минусов не ставил.
2) Я не считаю это проблемой, все равно интерфейс, определенный в MyThread будет привязан к конкретной задаче. Класс на практике называться будет соответственно этой задаче (а не MyThread). С другой стороны этот способ точно так же довольно просто поддаётся шаблонизации. Поэтому, если уже очень хочется, можно придумать нечто обобщённое на этой базе.
К слову сказать с более ранних версиях Qt event based межпоточное взаимодействие было основным способом. Т.к. во-первых поток не имел своей встроенной очереди сообщений, как в Qt4-Qt5, а во-вторых система сигналов не поддерживала межпоточные соединения. Приходилось делать свою очередь сообщений внутри run и проектировать систему событий для потока. Зато можно было передавать в основной поток события с помощью функции postEvent (собственно сейчас так тоже можно).
Одна из концепций такова (демонстрационный пример):
Со своей стороны нахожу данный подход одним из самых удачных для Qt и всем его рекомендую. Функции типа moveToThread считаю костылями, призванными исправлять существующие архитектурные косяки в проекте. Использовать их для новых решений ИМХО не стоит.
Аналогичный, более классический пример с использованием QEvent, который несколько более многословен, однако дает лучшую производительность.
Получается даже немного длинее. Нет, все-таки в этом случае право большинство: for и while — лучше.
Смысл «протаскивания» в том, что обработка исключения должна быть в том месте, где это нужно. Если переносить всю обработку в код враппера — это будет прямое нарушение инкапсуляции. Враппер просто не может знать об особенностях клиентского кода.
Причем я как раз отметил чем это чревато и почему нельзя такого допускать.
В чем идея? Есть либина XML, к ней есть С++ враппер. С++ враппер С++ библиотека? Да. Почему бы не использовать вместе с ней исключения. Однако в недрах враппера юзаются коллбэки, который выполняются в Си коде. Потому что враппер — над С-XML-либиной. Так как разрешить проблему? СС одной стороны как бы юзер враппера не виноват, он же юзает С++, с другой стороны ему вдруг нельзя использовать исключения. Это решение этой проблемы.
Шаблоны — для удобстве фильтрации. Если в mylib не один callback, а 10, и в каждом callback`е написано нечто вроде:
try
{
this_->callback();
}
catch(exception1)
{
}
catch(exceptionN)
{
}
Особенно если нужно добавить новое исключение, все это превращается в жуткую кашу. А у меня достаточно в одном месте дописать нужный тип в список исключений.
> Я не зря привел в пример expat. Проблема исключений встала именно при использовании этой
> библиотеки. Задача состояла в следующем:
> * Есть некий код, который раньше использовал библиотеку xml, написанную на С++ и этот код
> активно применял исключения;
> * Есть необходимость заменить библиотеку xml на другую без переписывания остального кода.
pureCLibSetUserData(this);
//...
MyLib * this_ = reinterpret_cast<MyLib*>(userData);
Предлагается решение, при котором такого вопроса бы не возникало. Исключение не должно покидать пределы С++.
> Предлагается костыль для кривых библиотек?
В C++ исключения — это нормальное явление, new кидает исключение, dynamic_cast кидает искючения, STL кидает исключения. Кривизна библиотеки будет только тогда, когда она позволит исключению попасть в чужую среду.
Пример на Си:
void foo(int (*callback)(char *))
{
char * buffer;
int ret;
buffer = malloc(100000);
ret = callback(buffer);
free(buffer);
}
Если сallback — это функция из С++, то она может бросить исключение. При этом будет утечка памяти, так как buffer не будет освобожден.