Minimal app:
TestProject.pro:
QT += core gui widgets
CONFIG += C++11
QMAKE_CXXFLAGS_RELEASE -= -O
QMAKE_CXXFLAGS_RELEASE -= -O0
QMAKE_CXXFLAGS_RELEASE -= -O1
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE *= -O3
QMAKE_CXXFLAGS_RELEASE -= -Os
QMAKE_CXXFLAGS_RELEASE -= -Ofast
TARGET = TestProject
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
main.cpp:
#include <mainwindow.h>
#include <QApplication>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QObject>
#include <QStack>
class Other : public QObject
{
Q_OBJECT
public:
explicit Other(QObject* parent = 0);
virtual ~Other();
void test();
private:
QStack<int> myStack;
};
//--------------------------------------------------------------------------------------------------
#include <QMainWindow>
#include <QPushButton>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = 0);
virtual ~MainWindow();
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
Other::Other(QObject* parent) :
QObject(parent)
{}
Other::~Other()
{}
void Other::test() //warning on this line
{
myStack.pop(); //but not when this line is commented
}
//--------------------------------------------------------------------------------------------------
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent)
{
(new Other(this))->test();
}
MainWindow::~MainWindow()
{}
Compiling with g++ -O3 -Wall gives this warning:
...TestProject/mainwindow.cpp:10: warning: assuming signed overflow does not occur when assuming that (X - c) <= X is always true [-Wstrict-overflow]
void Other::test() //warning on this line
^
Compiling with g++ -O2 -Wall does not.
This question makes sense, as it's for a conditional, but I'm not getting it on a conditional. I'm getting it on a function itself.
I'd like to use the more aggressive optimization, but still compile cleanly if I can. Is there something weird going on with QStack?
Update:
I still don't know what the warning is supposed to mean in this context, but I found a way to get rid of it.
I copied the code from qstack.h and pasted it into my own function, then called it instead of the built-in QStack::pop():
void Other::pop() //warning on this line
{
Q_ASSERT(!myStack.isEmpty());
int t = myStack.data()[myStack.size() - 1];
myStack.resize(myStack.size() - 1);
return t;
}
Still have the warning, but it's moved to the custom pop() function.
Then I played with it a bit and found that caching myStack.size() - 1 for the resize operation kills the warning, but only if it's done before extracting the data():
void Other::pop() //no warning
{
Q_ASSERT(!myStack.isEmpty());
int size = myStack.size() - 1;
int t = myStack.data()[myStack.size() - 1];
myStack.resize(size);
return t;
}
Using the cached value for both operations is also warning-free.
So that's one of probably several ways to get rid of it, but does anyone know why it occurs here?
The warning is telling you that the compiler is not checking if the result of the substraction is negative or not.
Why this matters in this particular line?
myStack.data()[myStack.size() - 1];
Because you are indexing an array (actually using a pointer variable, coming from the data() function, which returns a T*) using the result of a substraction operation, which may result in a negative number, which is, typically, something you don't want.
When you take that substraction and move it to a new variable, then the compiler sees that you are indexing an array directly with an int variable, and not the result of a substraction, so it does not warn anymore if the passed variable is negative or not.
About your comment, you are using the cached data for the resize function. I am not really sure about why this happens, but I guess it may be related that, in -O3 the compiler enables the following flag:
-finline-functions
See http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html for more details.
This flag enables all the inlining functions optimisation. Since you are using all templated classes, the compiler may be inlining all the involved functions, caching some results and somewhere is optimising the signed overflow. Probably in the if sentence in the resizefunction:
template <typename T>
void QVector<T>::resize(int asize)
{
int newAlloc;
const int oldAlloc = int(d->alloc);
QArrayData::AllocationOptions opt;
//Here, asize will be replaced with d->size - 1 after all the inlining.
//So the compiler is assuming that d->size - 1 will not overflow,
// because of undefined behaviour,
// instead of thinking that it may wrap.
if (asize > oldAlloc) {
newAlloc = asize;
opt = QArrayData::Grow;
} else {
newAlloc = oldAlloc;
}
reallocData(asize, newAlloc, opt);
}
But this is just a guess.
Related
I have studied the qt documentation of qRegisterMetaType() where it says that this function must be called before the corresponding type can be used in signal/slot mechanism. However I couldn't find any code example where this has to be done by hand.
This page states, that the registration is done automatically by the moc if it can determine that the type may be registered as meta-type. It looks like this is right, because I tested QSignalSpy, QObject::connect() (direct and queued connection) and QVariant - with just using Q_DECLARE_METATYPE(type) and none of them needed a explicit call to qRegisterMetaType to work.
So my question is: when do I have to call qRegisterMetaType(), because otherwise the code won't work?
The Qt docs say that Q_DECLARE_METATYPE is necessary in case one has a connect being a queued connection.
Adding a Q_DECLARE_METATYPE() makes the type known to all template
based functions, including QVariant. Note that if you intend to use
the type in queued signal and slot connections or in QObject's
property system, you also have to call qRegisterMetaType() since the
names are resolved at runtime.
For this I build a small testing app, that exemplifies the behavior.
Just try to remove the Q_DECLARE_METATYPE(Message) and watch the warnings and output change. In case of the normal connect the macro seems to be unnecessary.
main.cpp
#include <QApplication>
#include <QThread>
#include "MyHeaderView.h"
Q_DECLARE_METATYPE(Message);
int main(int argc, char **args)
{
QApplication app(argc, args);
{
TestObject sender;
TestObject receiver;
QObject::connect(&sender, &TestObject::sendMessage, &receiver, &TestObject::onMessage);
sender.emitMessage(1, 2);
}
// This requires Q_DECLARE_METATYPE(Message);
QThread workerThread;
TestObject sender2;
TestObject receiver2;
receiver2.moveToThread(&workerThread);
workerThread.start();
QObject::connect(&sender2, &TestObject::sendMessage, &receiver2, &TestObject::onMessage, Qt::ConnectionType::QueuedConnection);
sender2.emitMessage(3, 4);
app.exec();
}
TestObject.h
#pragma once
#include <QObject>
#include <QDebug>
struct Message
{
int x;
int y;
};
class TestObject : public QObject
{
Q_OBJECT
public:
void emitMessage(int x, int y) { emit sendMessage(Message{ x,y }); }
signals:
void sendMessage(const Message&);
public slots:
void onMessage(const Message& m) { qDebug() << m.x << m.y; }
};
Is it possible to create variadic signal and connect generic lambda as slot? I mean something like (say, all definitions of involved functions are visible where needed (e.g. at points of instantiation)):
#include <QCoreApplication>
#include <QObject>
#include <QTime>
class A
: public QObject
{
Q_OBJECT
public :
A(QObject * const parent = Q_NULLPTR)
: QObject{parent}
{ ; }
signals :
template< typename ...Ts >
void infoMessage(Ts... args);
public slots :
void run()
{
emit infoMessage("Started at ", QTime::currentTime());
}
};
#include <QTimer>
#include <QtDebug>
#include "main.moc"
int main(int argc, char * argv [])
{
QCoreApplication a{argc, argv};
A a;
auto printInfoMessage = [&] (auto... args)
{
(qInfo() << ... << args);
};
QObject::connect(&a, SIGNAL(infoMessage), printInfoMessage);
QTimer::singleShot(0, &a, &A::run);
return a.exec();
}
Currently it gives an error message:
AUTOGEN: error: process for main.cpp:18: Error: Template function as signal or slot
moc failed...
Here macro SLOT() instead of &A::infoMessage does not help a lot. Is there any workarounds to overcome this limitation?
I know, that some of the answers will contain a using of std::make_tuple and std::index_sequence stuff. But is there less verbose solution?
There is no direct workaround for having template. On of thea reason is that the moc indexes all signals and slots, and this cannot be done for function templates as function templates will generate several functions depending code that is generally not accessible from the moc.
I don't think you can make it work with tuple and such as these are also templates.
A solution could be to use QVariant and/or QVariantList for your arguments.
Please note that the error is not caused by the QObject::connect line, but the the signal declaration in class A.
Also, you cannot replace SIGNAL() and SLOT() at your will, it is either a signal or a slot, it cannot be both.
And finally you should be using this form:
QObject::connect(&a, &A::infoMessage, printInfoMessage);
And since printInfoMessage is using auto parameters, you might need to force the auto resolution using qOverload:
QObject::connect(&a, &A::infoMessage, qOverload<QVariantList>(printInfoMessage));
i'm following a tutorial to write a small piece of code of opengl in qt.here's the link
http://www.youtube.com/watch?v=1nzHSkY4K18
but in the 6:13 when I bluid the code it show a couple of error that
..\testopgl\glwidget.cpp: In member function 'virtual void GLWidget::paintGL()':
..\testopgl\glwidget.cpp:17:20: error: 'glColor3f' was not declared in this scope
..\testopgl\glwidget.cpp:19:25: error: 'glBegin' was not declared in this scope
..\testopgl\glwidget.cpp:20:31: error: 'glVertex3f' was not declared in this scope
..\testopgl\glwidget.cpp:23:11: error: 'glEnd' was not declared in this scope
..\testopgl\glwidget.cpp: At global scope:
what I really don't understand is when I only put the glClear(GL_COLOR_BUFFER_BIT) it builds alright,but occurs error even i just put the glColor3f().Does the GLWidget not support the glColor*() or glBegin() command?
here's my code.
testopgl.pro
#-------------------------------------------------
#
# Project created by QtCreator 2013-03-28T09:48:44
#
#-------------------------------------------------
QT += core gui opengl
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = testopgl
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
glwidget.cpp
HEADERS += mainwindow.h \
glwidget.h
FORMS += mainwindow.ui
glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QGLWidget>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);
void initializeGL();
void paintGL();
void resizeGL(int w,int h);
};
#endif // GLWIDGET_H
glwidget.cpp
#include "glwidget.h"
GLWidget::GLWidget(QWidget *parent) :
QGLWidget(parent)
{
}
void GLWidget::initializeGL(){
glClearColor(1,1,0,1);
}
void GLWidget::paintGL(){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,0,0);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5,-0.5,0);
glVertex3f(0.5,-0.5,0);
glVertex3f(0.0,0.5,0);
glEnd();
}
void GLWidget::resizeGL(int w,int h){
}
The functions you mention are simply not present in any modern version of GL, so the tutorial you are following sounds like it is quite out of date.
So probably the version of GL exposed through your build of QT does not have these functions. It may be possible to reconfigure/rebuild QT to use an older version of GL, but I would instead recommend getting to know and use the modern programmable interface.
#include <QtCore/QCoreApplication>
#include <QTCore>
#include <QtNetwork>
#include <QDebug>
#define CONNECT(sndr, sig, rcvr, slt) connect(sndr, SIGNAL(sig), rcvr, SLOT(slt))
class mynet : QObject
{
Q_OBJECT
public:
mynet()
{}
void start()
{
CONNECT(tcpServer, newConnection(), this, acceptConnection());
CONNECT(tcpClient, connected(), this, startTransfer());
CONNECT(tcpClient, bytesWritten(qint64), this, updateClientProgress(qint64));
CONNECT(tcpClient, error(QAbstractSocket::SocketError), this, displayError(QAbstractSocket::SocketError));
// start server listening
tcpServer->listen();
while(!tcpServer->isListening());
// make client connection
tcpClient->connectToHost(QHostAddress::LocalHost, tcpServer->serverPort());
}
public slots:
void acceptConnection()
{
tcpServerConnection = tcpServer->nextPendingConnection();
CONNECT(tcpServerConnection, readyRead(), this, updateServerProgress());
CONNECT(tcpServerConnection, error(QAbstractSocket::SocketError), this, displayError(QAbstractSocket));
tcpServer->close();
}
void startTransfer()
{
bytesToWrite = TotalBytes - (int)tcpClient->write(QByteArray(PayloadSize, '#'));
}
void updateServerProgress()
{
bytesReceived += (int)tcpServerConnection->bytesAvailable();
tcpServerConnection->readAll();
if (bytesReceived == TotalBytes)
{
qDebug() << "done";
tcpServerConnection->close();
}
}
void updateClientProgress(qint64 numBytes)
{
// callen when the TCP client has written some bytes
bytesWritten += (int)numBytes;
// only write more if not finished and when the Qt write buffer is below a certain size.
if (bytesToWrite > 0 && tcpClient->bytesToWrite() <= 4*PayloadSize)
bytesToWrite -= (int)tcpClient->write(QByteArray(qMin(bytesToWrite, PayloadSize), '#'));
}
void displayError(QAbstractSocket::SocketError socketError)
{
if (socketError == QTcpSocket::RemoteHostClosedError)
return;
qDebug() << tcpClient->errorString();
tcpClient->close();
tcpServer->close();
}
private:
QTcpServer* tcpServer;
QTcpSocket* tcpClient;
QTcpSocket* tcpServerConnection;
int bytesToWrite;
int bytesWritten;
int bytesReceived;
int TotalBytes;
int PayloadSize;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
mynet m1;
m1.start();
return a.exec();
}
I get an
Undefined symbols for architecture x86_64:
"vtable for mynet", referenced from:
mynet::mynet() in main.o
mynet::~mynet()in main.o.
Please advise what I am doing wrong. Can I not inline the method definitions in the class for some reason in Qt?
You need to add your class to the .pro file
HEADERS += mynet.h
SOURCES += mynet.cpp
so the meta-object compiler can scan them and work out they need moc'ing and generate the relevant stubs.
Assuming that your source file is named foo.cpp, you have to put the following line at the very end:
#include "foo.moc"
This line tells qmake and the VS Qt add-in that the file should be run via moc, and that the generated moc file should be named foo.moc.
You also have problems in the #include lines for Qt headers. I've found that the following work:
#include <QtCore/QCoreApplication>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
Make sure to add network to your .pro file. This will create the correct linking to the network library functions.
QT += core network
Two things:
1) You should publicly derive from QObject.
2) Are you moc'ing this file and then compiling and linking the output? If you include the Q_OBJECT macro and don't moc, you will get an error like that.
Following example from this link: http://developer.kde.org/documentation/books/kde-2.0-development/ch03lev1sec3.html
#include <QObject>
#include <QPushButton>
#include <iostream>
using namespace std;
class MyWindow : public QWidget
{
Q_OBJECT // Enable slots and signals
public:
MyWindow();
private slots:
void slotButton1();
void slotButton2();
void slotButtons();
private:
QPushButton *button1;
QPushButton *button2;
};
MyWindow :: MyWindow() : QWidget()
{
// Create button1 and connect button1->clicked() to this->slotButton1()
button1 = new QPushButton("Button1", this);
button1->setGeometry(10,10,100,40);
button1->show();
connect(button1, SIGNAL(clicked()), this, SLOT(slotButton1()));
// Create button2 and connect button2->clicked() to this->slotButton2()
button2 = new QPushButton("Button2", this);
button2->setGeometry(110,10,100,40);
button2->show();
connect(button2, SIGNAL(clicked()), this, SLOT(slotButton2()));
// When any button is clicked, call this->slotButtons()
connect(button1, SIGNAL(clicked()), this, SLOT(slotButtons()));
connect(button2, SIGNAL(clicked()), this, SLOT(slotButtons()));
}
// This slot is called when button1 is clicked.
void MyWindow::slotButton1()
{
cout << "Button1 was clicked" << endl;
}
// This slot is called when button2 is clicked
void MyWindow::slotButton2()
{
cout << "Button2 was clicked" << endl;
}
// This slot is called when any of the buttons were clicked
void MyWindow::slotButtons()
{
cout << "A button was clicked" << endl;
}
int main ()
{
MyWindow a;
}
results in:
[13:14:34 Mon May 02] ~/junkPrograms/src/nonsense $make
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/opt/qtsdk-2010.05/qt/mkspecs/linux-g++-64 -I. -I/opt/qtsdk-2010.05/qt/include/QtCore -I/opt/qtsdk-2010.05/qt/include/QtGui -I/opt/qtsdk-2010.05/qt/include -I. -I. -o signalsSlots.o signalsSlots.cpp
g++ -m64 -Wl,-O1 -Wl,-rpath,/opt/qtsdk-2010.05/qt/lib -o nonsense signalsSlots.o -L/opt/qtsdk-2010.05/qt/lib -lQtGui -L/opt/qtsdk-2010.05/qt/lib -L/usr/X11R6/lib64 -lQtCore -lpthread
signalsSlots.o: In function `MyWindow::MyWindow()':
signalsSlots.cpp:(.text+0x1a2): undefined reference to `vtable for MyWindow'
signalsSlots.cpp:(.text+0x1aa): undefined reference to `vtable for MyWindow'
signalsSlots.o: In function `MyWindow::MyWindow()':
signalsSlots.cpp:(.text+0x3e2): undefined reference to `vtable for MyWindow'
signalsSlots.cpp:(.text+0x3ea): undefined reference to `vtable for MyWindow'
signalsSlots.o: In function `main':
signalsSlots.cpp:(.text+0x614): undefined reference to `vtable for MyWindow'
signalsSlots.o:signalsSlots.cpp:(.text+0x61d): more undefined references to `vtable for MyWindow' follow
collect2: ld returned 1 exit status
make: *** [nonsense] Error 1
vtable is for virtual functions, AFAIK, what's the reason of error here?
It looks like moc doesn't generate code for your QObject because you declare it in the .cpp file. The easiest way to fix that is to move the declaration of MyWindow to a header, and add the header to the HEADERS list, in the .pro file:
HEADERS += yourheader.h
Then rerun qmake.
(Please note that the KDE 2.0 book you look at is vastly outdated)
Maybe too late but... Had the same issue and fighted for a while to find where it comes from.
Right click on your project and select “Run qmake” to for a new build of MOC classes. It usually does run automatically...
The moc compiler generates the stubs and calls in moc_xxxx.cpp, and generates the vtable stuff
Just Change your Main() as follows:
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWindow w;
w.show();
return a.exec();
}
Based on andref comment just above, when everything is in one cpp file like stuff.cpp, you need to add at the end of the file:
#include "moc_stuff.cpp"
(this is with Qt 4.7.0)
This issue may be caused by some of the following reasons. I have stumbled on all of them from time to time.
Your class header may be missing the Q_OBJECT macro. Add the macro to the header as already noted by other answers.
class MyWidg : public QWidget
{
Q_OBJECT
Your class header may not be parsed by the moc. Add the header file in the HEADERS definitions of your .pro (or .pri) project file.
HEADERS += file.h
If none of the above is true, then you probably need to run qmake again to make sure moc parses the header again, just in case the Q_OBJECT macro was added in the header after the qmake was run. Just run qmake again.