Extend QDebug and suppress messages - c++

We need to suppress qDebug() messages when tracing is disabled.
I know the qInstallMessageHandler() an we are using it but we need an additional trace method.
class MyDebug : public QDebug {
public:
explicit MyDebug();
MyDebug(const QDebug &o);
MyDebug(const MyDebug &o);
private:
std::shared_ptr<QString> null_string;
static void doDeleteLater(QString *obj);
};
MyDebug::MyDebug()
: null_string(new QString(), &MyDebug::doDeleteLater), QDebug(null_string.get()) {
qCritical("construct");
}
void MyDebug::doDeleteLater(QString *obj) {
qCritical("delete");
}
MyDebug::MyDebug(const QDebug &o)
: QDebug(o) {
qCritical("called1");
}
MyDebug::MyDebug(const MyDebug &o)
: null_string(o.null_string), QDebug(null_string.get()) {
qCritical("called2");
}
MyDebug Application::trace(const uchar verbosity) const {
MyDebug d = this->logLevel > 6 ? MyDebug(qDebug()) : MyDebug();
// QDebug default verbosity is 2 - Range 0-7
d.setVerbosity(qMin((uchar)7, verbosity));
return d;
}
Now using the Application::trace() results in errors
Application::trace() << QString("test");
...
construct
QTextStream: No device
delete
I thought it has to do with the lifetime of null_string when MyDebug is copied, but the copy constructor is never called.
Using a heap constructed QString* as QDebug device is working.

Install a custom handler like:
#include <QtGlobal>
QtMessageHandler DEFAULT_MSG_HANDLER = 0;
void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
if (type == QtDebugMsg) {
// Ignores debug.
return;
}
// Redirects anything else to the default handler.
(*DEFAULT_MSG_HANDLER)(type, context, msg);
}
int main(int argc, char **argv)
{
DEFAULT_MSG_HANDLER = qInstallMessageHandler(myMessageHandler);
QApplication app(argc, argv);
// ...
return app.exec();
}

Related

C++11 multithreaded cancellable slice-based work

I am trying to create a base class to manage a slice-based workload.
My approach was to create a base abstract class that handles the initialization/termination of the work and inherit from that class in specific classes that only specify the actual work and timings.
I also added the functionality in the base class to reinitialize the workload if a set number of errors occur.
This works as expected in a simple example (given below) and with most workloads that I have but when I try to use this with a specific workload (reading a serial port that's written to by an arduino) it completely messes up the stream read from arduino.
I suspect there is some problem with my approach but I couldn't figure it out...
Here is my code:
sliceWork.h
#pragma once
#include <future>
using namespace ::std;
class sliceWork
{
int sliceIntervalMilliSeconds;
int failureCounter;
int maxFailsBeforeRestart;
char* label = NULL;
promise<void> workPromise;
thread* workerThread = NULL;
virtual void init() = 0;
virtual bool oneSliceWork() = 0;
void work(future<void> future);
public:
sliceWork(int sliceInterval, int maxFails, const char* label);
~sliceWork();
void initWork();
void signalTerminate();
};
sliceWork.cpp
#include <string.h>
#include "sliceWork.h"
sliceWork::sliceWork(int interval, int maxFails, const char* workLabel)
{
sliceIntervalMilliSeconds = interval;
maxFailsBeforeRestart = maxFails;
label = new char[strlen(workLabel) + 1];
strcpy(label, workLabel);
}
sliceWork::~sliceWork()
{
if (workerThread != NULL && workerThread->joinable())
workerThread->join();
printf("destructor %s\n", label);
delete label;
delete workerThread;
}
void sliceWork::initWork()
{
failureCounter = 0;
init();
printf("Init work %s finished!\n", label);
future<void> futureWorker = workPromise.get_future();
workerThread = new thread(&sliceWork::work, this, move(futureWorker));
}
void sliceWork::work(future<void> future)
{
using namespace ::std::chrono;
steady_clock::time_point t0 = steady_clock::now();
while (future.wait_for(chrono::milliseconds(1)) == future_status::timeout)
{
if (duration_cast<chrono::milliseconds>(steady_clock::now() - t0).count()
> sliceIntervalMilliSeconds)
{
if (!oneSliceWork())
{
if (++failureCounter > maxFailsBeforeRestart
&& maxFailsBeforeRestart > 0)
{
init();
failureCounter = 0;
}
}
t0 = steady_clock::now();
}
}
printf("work terminated for %s!\n", label);
}
void sliceWork::signalTerminate()
{
printf("request terminate for work %s...\n", label);
workPromise.set_value();
}
And here is an example of using it that works as expected:
main.cpp
#include <string.h>
#include "sliceWork.h"
class A : public sliceWork
{
void init() {
printf("Init A...\n");
}
bool oneSliceWork() {
printf("Working A...\n");
return true;
}
public:
A(int slice, int max, const char* label)
: sliceWork(slice, max, label)
{
}
};
class B : public sliceWork
{
void init() {
printf("Init B...\n");
}
bool oneSliceWork() {
printf("Working B...\n");
return true;
}
public:
B(int slice, int max, const char* label)
: sliceWork(slice, max, label)
{
}
};
class C : public sliceWork
{
void init() {
printf("Init C...\n");
}
bool oneSliceWork() {
printf("Working C...\n");
return false;
}
public:
C(int slice, int max, const char* label)
: sliceWork(slice, max, label)
{
}
};
int main()
{
{
A a(1000, 1000, "A");
a.initWork();
B b(2000, 1000, "B" );
b.initWork();
C c(700, 2, "C" );
c.initWork();
printf("Initializations finished!\n");
::std::this_thread::sleep_for(::std::chrono::seconds(7));
a.signalTerminate();
::std::this_thread::sleep_for(::std::chrono::seconds(5));
b.signalTerminate();
::std::this_thread::sleep_for(::std::chrono::seconds(4));
c.signalTerminate();
}
getchar();
return 0;
}
So, I want to ask if this approach is prone to error because the way I implemented the functionality.
Application is written in C++11 and targets an Raspberry PI 3b+ running the Raspberry's flavor of Debian 11 (Raspbian), if that is relevant.
Since C++11 we use keyword nullptr instead of NULL macro. Moreover, std::thread is movable, so it is much better to use it as value rather than pointer:
class sliceWork{
///...
std::thread workerThread;
///...
~sliceWork(){
///...
if (workerThread.joinable())
workerThread.join();
///...
};
///...
void initWork(){
///...
workerThread = thread{[this](){
work(workPromise.get_future());
}};
///...
};
};
I used a lambda to initialize the thread instead of your original code; it has better minimally performance, while more readable IMO.
If you can use C++17, then I strongly recommend using std::string_view over old null-terminated strings; otherwise just use std::string. Also using constructor member initializer list is always recommended:
#include <string>
class sliceWork{
///...
std::string_view label;
///...
sliceWork(int interval, int maxFails, std::string_view workLabel):
sliceIntervalMilliSeconds {interval},
maxFailsBeforeRestart {maxFails},
label {workLabel}
{};
///...
};
If you can use C++20 however, std::jthread is of huge advantages over std::thread. Because now that you already don't delete the label or workerThread and the destructor of std::jthread automatically joins, you can totally drop the destructor of sliceWork; the default compiler-provided destructor will do!! Plus, you can even get rid of the workPromise:
class sliceWork{
///...
std::string_view label;
///...
std::jthread workerThread;
///...
//std::promise<void> workPromise;//we don't need this
///...
//~sliceWork()=default;
///...
void signalTerminate(){
///...
workerThread.request_stop();
}
///...
void initWork(){
///...
workerThread = jthread{[this](std::stop_token stop_token){
work(std::move(stop_token));
}};
///...
};
///...
void work(std::stop_token stoken){
///...
for(int ticks{0}; !stoken.stop_requested(); sleep_for(chrono::milliseconds(1)), ++ticks) {
if (ticks > sliceIntervalMilliSeconds) {
///...
}; //if
///...
}; //for
///...
};//work
};
One final word: almost never use printf; it has lots of caveats. In C++ we use std::cout. In multi_threaded applications, end the std::cout instructions with << std::endl; this flushes the buffer and helps the output to be more readable.

How does a function in Qt accept passed arguments from two places?

I want to wirte a funtion CH1_Hard_Soft to process data, which accepts two arguments from two different function.
double MainWindow::getdata_CH1(double time)
{
...
double CH1_data=0;
switch (CH1.Source) {
case 0: //software-hard
CH1_data = CH1_Hard_Soft(time);
....
}
The function CH1_Hard_Soft need to accept an argument time from getdata_CH1 and accept a QVector from other thread. And the function CH1_Hard_Soft will process these data and then return a QVector to getdata_CH1(double time). I don't know how to do this. Please give me some suggestions on how to do this.THANKS!!!
You can use a Function Object: create a new class with two attributes (one per parameter). Create setter for each parameter (or redefine the operator () to be closer to the behavior of a real function).
Each setter should check if the others are setted also. In that case, call you algorithm and send the result with a signal.
For example:
A simple worker executed in another thread. It will send fake data after 3 seconds
class Worker: public QObject
{
Q_OBJECT
public:
Worker(): QObject()
{
}
void timerEvent(QTimerEvent* ev)
{
qDebug() << Q_FUNC_INFO;
emit getVector(QVector<int>() << 2 << 4 << 6 << 8);
killTimer(timerId);
}
public slots:
void run()
{
timerId = startTimer(3000);
}
signals:
void getVector(QVector<int> const& vec);
private:
int timerId;
};
The Function Object: it will accept two param (a double and a vector)
// For convenience. Define a value and a flag to check if the value is well set
template<typename T> struct Param
{
T value;
bool isInit;
Param(): isInit(false)
{}
void setValue(T const& v)
{
value = v;
isInit = true;
}
};
// The processor
class Processor: public QObject
{
Q_OBJECT
public:
Processor(QObject* parent=nullptr): QObject(parent)
{}
void operator()(QVector<int> const& vector)
{
values.setValue(vector);
if (time.isInit)
process();
}
void operator()(double t)
{
time.setValue(t);
if (values.isInit)
process();
}
signals:
void done(double result);
private:
// Will be called as soon as all the parameters are set
void process()
{
// DO something
qDebug() << Q_FUNC_INFO;
emit done(time.value * values.value.length());
}
Param<QVector<int> > values;
Param<double> time;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Run the thread
Worker* worker = new Worker();
QThread* th = new QThread();
worker->moveToThread(th);
QObject::connect(th, &QThread::started, worker, &Worker::run);
Processor CH1_Hard_Soft;
// Will be called when the CH1_Hard_Soft will send its result
QObject::connect(&CH1_Hard_Soft, &Processor::done, [=](double result) { qDebug() << "RESULT" << result; });
// Set the param vector
QObject::connect(worker, &Worker::getVector, [&](QVector<int> const& vec) { CH1_Hard_Soft(vec); });
// Call CH1_Hard_Soft with the first param
double time = 12.6;
CH1_Hard_Soft(time);
th->start();
return app.exec();

lua_newuserdata placement new on QMetaObject

I'm trying to integrate Lua with Qt's QMetaObject system. I have a class that derives from QObject that I bind to Lua based on the class name using QObject::staticMetaObject.
main.h:
#ifndef MAIN_H
#define MAIN_H
class Test : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE Test(QObject *parent = 0) : QObject(parent){}
~Test(){}
};
Q_DECLARE_METATYPE(Test*)
#endif
main.cpp
#include <QCoreApplication>
#include <QDebug>
#include "main.h"
#include "lua_src/lua.hpp" //Lua include
int CreateUserData(lua_State *L)
{
const QMetaObject *metaObject = (const QMetaObject*)lua_touserdata(L, lua_upvalueindex(1));
//PROBLEM AREA
int typeId = QMetaType::type(metaObject->className());
if(typeId != QMetaType::UnknownType)//typeId is always unknown
{
QMetaType meta(typeId);
void *ptr = lua_newuserdata(L, meta.sizeOf());
meta.construct(ptr);
}
//PROBLEM AREA
lua_newtable(L);
lua_setuservalue(L, 1);
return 1;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString luaScript("local test = Test.new()");
lua_State *L = luaL_newstate();
//bind Test class to lua
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setglobal(L, "Test");
lua_pushvalue(L, -1);
lua_pushlightuserdata(L, (void*)&Test::staticMetaObject);
lua_pushcclosure(L, CreateUserData, 1);
lua_setfield(L, -2, "new");
//start script
luaL_dostring(L, luaScript.toStdString().c_str());
lua_close(L);
}
The issue is that lua will allocate memory for userdata but will not construct the object it represents. All documentation says to use placement new to construct your object at the ptr of the lua userdata, however QMetaObject doesn't allow placement new out of the box.
I've included suggestions from ixSci about using QMetaType to construct the object at ptr. However, typeId always comes back as unknown.
Looks like what you need is available in the QMetaType class.
So to get what you ask for you need something like this (not tested!):
int typeId = QMetaType::type(metaObject->className());
if (typeId != QMetaType::UnknownType)
{
QMetaType meta(typeId);
meta.construct(ptr, objectToCopy);
}
Your Test class miss a
Q_DECLARE_METATYPE(Test*)
and a
qRegisterMetaType<Test*>("Test");
to have the type correctly registered in Qt Meta-system.
Note the pointer declared. You need to declare a pointer because the copy constructor is disabled for QObject.
than you can correctly call:
Test* test = new Test();
auto name = test.metaObject()->className();
auto type = QMetaType::type(name);
Test* instance = static_cast<Test*>(QMetaType::construct(type));
Edit: A complete working implementation (it actually add the qMetaTypeConstructHelper)
somevalue.h
#include <QObject>
#include <QMetaType>
class SomeValue : public QObject
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit Q_INVOKABLE SomeValue(QObject* parent = nullptr);
~SomeValue() override = default;
int value() const;
signals:
void valueChanged(int value);
public slots:
void setValue(int value);
private:
int _value;
};
somevalue.cpp
#include "somevalue.h"
Q_DECLARE_METATYPE(SomeValue*)
template <>
void* qMetaTypeConstructHelper<SomeValue>(const SomeValue*)
{
return new SomeValue();
}
static struct SomeValueMetaId
{
SomeValueMetaId()
{
qRegisterMetaType<SomeValue>("SomeValue");
}
} _SomeValueMetaId;
SomeValue::SomeValue(QObject* parent)
: QObject(parent),
_value{100}
{
}
int SomeValue::value() const
{
return _value;
}
void SomeValue::setValue(int value)
{
if (_value == value)
return;
_value = value;
emit valueChanged(_value);
}
main.cpp
int main()
{
SomeValue pint;
auto pintName = pint.metaObject()->className();
auto pintType = QMetaType::type("SomeValue");
qDebug() << pintName << pintType << QMetaType::typeName(pintType);
qDebug() << QMetaType::isRegistered(QMetaType::type("SomeValue*"));
auto otherObj = static_cast<SomeValue*>(QMetaType::construct(pintType));
qDebug() << pint.value();
qDebug() << otherObj->value();
qDebug() << "new classname" << otherObj->metaObject()->className();
qDebug() << otherObj->metaObject()->propertyCount();
int valueId = pint.metaObject()->indexOfProperty("value");
auto minname = pint.metaObject()->property(valueId).name();
qDebug() << "value name" << minname;
auto minvariant = pint.property(minname);
qDebug() << "value type name" << minvariant << minvariant.typeName();
qDebug() << QMetaType::type(minvariant.typeName());
return 0;
}
I have found a solution for my situation.
After reviewing the answers from Moia and ixSci, I have realized that I was correct in my statement that placement new cannot be used on a QObject because QObject has it's copy constructor private (and shouldn't be made public).
A more efficient method is to (obviously) store pointers to the QObject* created from metaObject->newInstance(). That's right, pointers to pointers.
New code is as follows:
const QMetaObject *metaObject = (const QMetaObject*)lua_touserdata(L, lua_upvalueindex(1));
uintptr_t *ptr = (uintptr_t*)lua_newuserdata(L, sizeof(QObject*));
QObject *object = metaObject->newInstance();
*ptr = reinterpret_cast<uintptr_t>(object);
And for retrieving:
uintptr_t *objectPointer = (uintptr_t*)lua_touserdata(L, -1);
QObject *object = static_cast<QObject*>((void*)*objectPointer);
The upside is that lua can allocate fixed size for any class object since it is always 4 (just a pointer). This means I don't have to do any type checking.
The obvious downside to this is that I can't do any type checking since it will always just be pointers. Also, all interactions with these types inside the Lua script will behave as pointers. All copies will be pointer copies instead of QObject copies. As a result, I will have to implement my own copy constructor for my QObject's depending on my specific use case.
Thanks for all your assistance!

Does deleteLater() of Qt5.7 depend of the operative system?

Good day everyone, I discovered a bug in my code, that is:
I have a list of pointers to QLocalSocket and in the destructor I close and delete them with the following piece of code
for ( int i = 0; i < localSocketsList.size(); i++ )
{
if ( localSocketsList.at(i) != NULL )
{
localSocketsList.at(i)->close();
localSocketsList.at(i)->deleteLater();
}
}
The bug was that I previously connected a slot with the disconnected() signal of the sockets, and the slot delete them as well with the code:
QMutableListIterator<QLocalSocket *> iterator(localSocketsList);
while( iterator.hasNext() )
{
QLocalSocket * currentLocalSocket = iterator.next();
if ( currentLocalSocket -> state() == QLocalSocket::UnconnectedState )
{
currentLocalSocket -> deleteLater();
iterator.remove();
}
}
Ok right now you can see the error, I try to delete a pointer twice and I have a crash. BUT, it took me a while to detect this error because I did not observe a crash in Windows 10, only in Windows 7.
The question is: is there some difference in the deleteLater() function of Qt5.7 depending of the operative system? Shouldn't this problem appear in all platforms, since it is a c++ run time error?
Maybe is something depending of how Qt schedules the job (I mean, finishing the for cycle before sending the signals)? In that case is the schedule of the jobs depending of the OS? Shouldn't this be almost "random"?
Thanks everybody
It is valid to invoke deleteLater multiple times before the control returns to the event loop:
#include <QtCore>
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
auto obj = new QObject;
obj->deleteLater();
obj->deleteLater();
connect(obj, &QObject::destroyed, []{ qApp->quit(); });
return app.exec();
}
Thus, it seems to me that your problem isn't in invoking deleteLater multiple times, but iterating over a collection of objects that have been destroyed. The localSocketList is not aware of the sockets being deleted and contains dangling pointers.
There's a simple remedy for that - use a list that is aware of objects being deleted. For simplicity, the list below is explicitly shared, i.e. any of its copies refer to the same object (those are also JavaScript semantics, if you're familiar with them).
// https://github.com/KubaO/stackoverflown/tree/master/questions/qobject-pointer-list-43986348
#include <QtCore>
class PointerListData : public QObject, public QSharedData {
Q_OBJECT
public:
QVector<QObject*> list;
void removed() { list.removeAll(sender()); }
void connect(QObject* obj) {
QObject::connect(obj, &QObject::destroyed, this, &PointerListData::removed);
}
void disconnect(QObject* obj) {
QObject::disconnect(obj, &QObject::destroyed, this, &PointerListData::removed);
}
};
template <typename T> class PointerList {
protected:
QExplicitlySharedDataPointer<PointerListData> d;
public:
PointerList() : d(new PointerListData) {}
PointerList(const PointerList &other) : d(other.d) {}
PointerList(PointerList && other) : d(std::move(other.d)) {}
void append(T* obj) {
auto connect = !contains(obj);
d->list.append(obj);
if (connect)
d->connect(obj);
}
PointerList & operator<<(T* obj) {
append(obj);
return *this;
}
int removeAll(T* obj) {
auto n = d->list.removeAll(obj);
if (n)
d->disconnect(obj);
return n;
}
bool contains(T* obj) const {
return d->list.contains(obj);
}
void clear() {
for (auto obj : d->list)
d->disconnect(obj);
d->list.clear();
}
void moveToThread(QThread* thread) { d->moveToThread(thread); }
bool isEmpty() const { return d->list.isEmpty(); }
int size() const { return d->list.size(); }
using iterator = T**;
using const_iterator = const T**;
iterator begin() { return iterator(d->list.data()); }
iterator end() { return iterator(d->list.data() + d->list.size()); }
const_iterator begin() const { return const_iterator(d->list.constData()); }
const_iterator end() const { return const_iterator(d->list.constData() + d->list.size()); }
constexpr const PointerList& crange() const noexcept { return *this; }
// see http://stackoverflow.com/q/15518894/1329652
};
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
PointerList<QMimeData> list;
{
QMimeData a;
QMimeData b;
list << &a << &b;
auto list2 = list;
Q_ASSERT(list2.size() == 2);
for (auto obj : list.crange())
qDebug() << obj;
}
Q_ASSERT(list.isEmpty());
}
#include "main.moc"

Return a mocked object from a mocked object in Google mock

I have the following setup:
class MockObject : public Parent
{
public:
MOCK_CONST_METHOD0( GetSecondMockedObject, const Parent&() );
MOCK_CONST_METHOD0( SomethingReturnsBool, const bool() );
};
I have
MockObject mockParentObj;
MockObject mockChildObj;
// I create the following expectation on mockChildObj
EXPECT_CALL( mockChildObj, SomethingReturnsBool() ).WillRepeatedly( Return( true ) );
// I create the following expectation on mockParentObj
EXPECT_CALL( mockParentObject, GetSecondMockedObject() ).WillRepeatedly( ReturnRef( mockChildObj ) );
// I am going to use the parent mock object somewhere
realProductionObject.SomeRealFunction( mockParentObject );
// Definition of SomeRealFunction is part of the production code
SomeRealFunction( Parent& pObject )
{
// Method #1
// This should call the parent mock object which should return the child
// mock object. Then on that object I call SomethingReturnsBool()
// and the value of "val" should be true.
const Parent& childObject = pObject.GetSecondMockedObject().
bool val = childObject.SomethingReturnsBool();
// Method #2
// This also throws an error
// bool val = pObject.GetSecondMockedObject().SomethingReturnsBool();
}
However, when I execute the code( which is a bit different than this code and it compiles without an issue) I get the following exception and it is caused by the call to SomethingReturnsBool():
First-chance exception at 0x023CC193 in MyTest.exe: 0xC0000005: Access violation reading location 0xCCCCCCE8.
Critical error detected c0000374
I am suspecting that the child mock object reference returned from the call GetSecondMockObject() is invalid. I am not sure how else to pass it? I tried using:
ReturnPointee( &... ) instead of ReturnRef( ... ) but that also didn't work.
I would appreciate any suggestions!
Your SomeRealFunction(Parent pObject) you need to pass a reference or pointer because you lost your mock configuration on copy object.
My code follow run without problems:
#include <iostream>
#include <vector>
#include <assert.h>
#include "gtest/gtest.h"
#include "gmock/gmock.h"
using namespace std;
using namespace testing;
class Parent
{
public:
virtual ~Parent() {}
Parent() {}
virtual const Parent& GetSecondMockedObject() const { return *this; }
virtual const bool SomethingReturnsBool() const { return false; }
};
class MockObject : public Parent
{
public:
MOCK_CONST_METHOD0( GetSecondMockedObject, const Parent&() );
MOCK_CONST_METHOD0( SomethingReturnsBool, const bool() );
};
class MyRealObject
{
public:
// Definition of SomeRealFunction is part of the production code
void SomeRealFunction(const Parent& pObject )
{
std::cout << "parent = " << &pObject << std::endl;
const Parent& childObject = pObject.GetSecondMockedObject();
std::cout << "child = " << &childObject << std::endl;
bool val = childObject.SomethingReturnsBool();
std::cout << "val = " << val << std::endl;
}
};
TEST(mytest, tehet)
{
MockObject mockParentObj;
MockObject mockChildObj;
EXPECT_CALL(mockChildObj, SomethingReturnsBool() ).WillRepeatedly( Return( true ) );
EXPECT_CALL(Const(mockParentObj), GetSecondMockedObject() ).WillRepeatedly( ReturnRef( mockChildObj ) );
MyRealObject myobj;
myobj.SomeRealFunction(mockParentObj);
}
int main(int argc, char *argv[]) {
::testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
}