Doesn't `QPoint` support `std::unique_ptr`? - qt

I want to store QPoint in an object, which should be released automatically.
#include <QCoreApplication>
#include <memory>
#include <QPoint>
using namespace std;
class MyWidget{
public:
vector<std::unique_ptr<QPoint>> _points;
void f(QPoint point){
std::unique_ptr<QPoint> pos(new QPoint(point));
_points.push_back(pos);
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyWidget wid;
wid.f(QPoint(0,0));
return a.exec();
}
The error message is:
F:\Qt\Qt5.5.0\Tools\mingw492_32\i686-w64-mingw32\include\c++\ext\new_allocator.h:120:
error: use of deleted function 'std::unique_ptr<_Tp,
_Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = QPoint; _Dp = std::default_delete]' { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^
Does it mean that I am not supposed to use unique_ptr to store QPoint?

No, the problem is that you can't push_back a copy of a unique_ptr.
Use push_back(std::move(ptr)) or emplacement construction.
Apart from this, I don't see the need to dynamically allocate a value class such as QPoint.

On 64 bit platforms, sizeof(QPoint*) == sizeof(QPoint): the pointer has the same size as the pointed-to-object in the case of QPoint. Moving around the pointers in a vector is no faster than moving around the point values. You're prematurely pessimizing by dynamically allocating these small things one-by-one.
Even on a 32 bit system, the overhead of dynamic allocation will have the performance suffer unnecessarily.
Use a QVector<QPoint> or std::vector<QPoint>, they'll all perform well with points.
TL;DR: Understand the data types that you use, especially if they are simple tuples of integers as QPoint is.

Related

writeTextElement() of QXmlStreamWriter crashed when writting the content of a big file

Here is the qt code that crash:
Writing the content of a 130MB binary file will crash, but writing a 2MB binary file will not.
Is there any solution for writeTextElement to write big file content? Thanks
env: qt opensource 4.8.7
Visual Studio 2010
Windows 10
big file: https://1drv.ms/u/s!Ap_EAuwC9QkXijOmXqxp9DEav3gm?e=iha0uI
test project: https://1drv.ms/u/s!Ap_EAuwC9QkXijWzOlpaWmtzOdtz?e=fDpo93
#include <QtCore/QCoreApplication>
#include <QFile>
#include <QXmlStreamWriter>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QByteArray mContentBuffer;
QFile file("C:\\Work\\bigfile.xar");
if(!file.open(QFile::ReadOnly))
{
return -1;
}
mContentBuffer = file.readAll();
file.close();
QFile profile("C:\\Work\\profile.xml");
if(!profile.open(QFile::WriteOnly|QFile::Truncate))
{
return -1;
}
QXmlStreamWriter stream(&profile);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("Profile");
stream.writeTextElement("Content", mContentBuffer.toBase64());
stream.writeEndElement(); // Profile
stream.writeEndDocument();
return a.exec();
}
The minimal reproducible example was a life saver.
Several things seem to be required to solve your issue in a clean way.
Mainly, the file must be read in chunks.To be precise and as mentioned in that other question, in chunks whose size is a multiple of 3 bytes (I have hardcoded 9000 below).You will need to look for the value that gives you the best performance while guaranteeing it never fails yourself.
Instead of writing in the XML in 1 go, I made it so the XML file is being written each chunk at a time.To achieve that, the code creates the node first, then uses the writeCharacters method to write text in it.
Note the if (mContentBuffer.isEmpty()) right before writing. It is indeed specified in Qt Assistant that the read function has no way of reporting errors; returning an empty QByteArray can mean either that no data was currently available for reading, or that an error occurred. Considering the while loop, it can only be an error, so we abort everything.BTW, I think but have not tested that you can just end the document, and the XML stream writer will close everything it needs to have a valid XML.
Just to make it clean, I reordered the lines of codes so that the XML file is opened before the xar file. I also added QtCore/ on every include. Not sure that last point is going to be useful on your real code.
This code implements all the above changes.It should not crash and while you will not be able to test the output on the 130MB file, you should be able to test your code vs mine on the 2MB file you has successfully read from before.
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QXmlStreamWriter>
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
QFile profile("C:\\Work\\profile.xml");
if (!profile.open(QFile::WriteOnly | QFile::Truncate))
return -1;
QXmlStreamWriter stream(&profile);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("Profile");
stream.writeStartElement("Content");
QFile file("C:\\Work\\bigfile.xar");
if (!file.open(QFile::ReadOnly))
return -1;
while (!file.atEnd()) {
QByteArray mContentBuffer = file.read(9000);
if (mContentBuffer.isEmpty()) {
stream.writeEndDocument();
file.close();
profile.close();
return -1;
}
stream.writeCharacters(mContentBuffer.toBase64());
}
file.close();
stream.writeEndElement(); // </Content>
stream.writeEndElement(); // </Profile>
stream.writeEndDocument();
return a.exec();
}

Qt QFile / QTemporaryFile cannot read or write

I have no idea why, but i can´t get the simplest example of QTemporaryFile to run... My real intent is to write data from QAudioInput into a temporary file before it is processed later.
After trying several times I realized that neither .read(), .readLine(), .readAll() or .write() would have any effect... The error string is always "Unknown Error" and it neither works for QFile or QTemporaryFile.
#include <QCoreApplication>
#include <QTemporaryFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTemporaryFile tf;
tf.open();
tf.write("Test");
QTextStream in(&tf);
qDebug() << "Testprogramm";
qDebug() << tf.isOpen();
qDebug() << tf.errorString();
qDebug() << in.readLine();
qDebug() << tf.readAll();
tf.close();
return a.exec();
}
The debug posts:
Testprogramm
true
"Unknown error"
""
""
Thank you in advance!
You need to move the file pointer back to the beginning of the file. This has to be done on the file itself when there's no stream on the file, or using the stream when one exists. Also - QFile is a proper C++ class that manages the file resource. There's no need to manually close the file. QFile::~QFile does that job.
The following works just fine:
#include <QtCore>
int main() {
auto line = QLatin1String("Test");
QTemporaryFile tf;
tf.open();
Q_ASSERT(tf.isOpen());
tf.write(line.data());
tf.reset(); // or tf.seek(0)
QTextStream in(&tf);
Q_ASSERT(in.readLine() == line);
in.seek(0); // not in.reset() nor tf.reset()!
Q_ASSERT(in.readLine() == line);
}
The above also demonstrates the following techniques applicable to sscce-style code:
Inclusion of entire Qt module(s). Remember that modules include their dependencies, i.e. #include <QtWidgets> is sufficient by itself.
Absence of main() arguments where unnecessary.
Absence of QCoreApplication instance where unnecessary. You will get clear runtime errors if you need the application instance but don't have one.
Use of asserts to indicate conditions that are expected to be true - that way you don't need to look at the output to verify that it is correct.
Use of QLatin1String over QStringLiteral where ASCII strings need to be compared to both C strings and QStrings. Implicit ASCII casts can be a source of bugs and are discouraged.
QLatin1String is a constant (read-only) wrapper, designed to wrap C string literals - thus there's no need to make line additionally const, although in real projects you'd want to follow the project's style guide here.

Why QMimeData is returning invalid QStringList at each call of member func formats()?

I was trying to use a for each [Modern c++ style] but the code is crashed each time!
It was something like :
for(auto &k:mimeData->formats())
{ ... }
And later out of my surprises I found that the QStringList returned by formats is either invalid or completely separate object though the internal data is ought to be same!
So I tried to figure out in more simple example :
#include <iostream>
#include <string>
#include <list>
#include <QCoreApplication>
#include <QMimeData>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<boolalpha;
list<string> ls;
cout<<(ls.begin() != ls.end())<<"\n";
QStringList qsl;
cout<<(qsl.begin() != qsl.end())<<"\n";
QMimeData qme;
cout<<(qme.formats().begin() != qme.formats().end())<<"\n";
cout<<"OMG! is it empty? -> "<<qme.formats().empty()<<"\n";
return a.exec();
}
The output is something like :
false
false
true
OMG! is it empty? -> true
Until or unless I take an rvalue reference I cant decide what is happening internally!
I really need a solution to use it with range based for loops, not Qt's foreach!
P.S. I dont want to copy it to avoid O(n).
Looking at the docs, there's no guarantee QMimeData class keeps QStringList of supported formats (http://doc.qt.io/qt-4.8/qmimedata.html#formats) as a field.
The source code supports that (Qt5.4/Src/qtbase/src/corelib/kernel/qmimedata.cpp:593):
QStringList QMimeData::formats() const
{
Q_D(const QMimeData);
QStringList list;
for (int i=0; i<d->dataList.size(); i++)
list += d->dataList.at(i).format;
return list;
}
Therefore this list is constructed on every call to formats(). Farther calls to it will always yield a separate container.
Since you do need to preserve it to traverse it, I'd recommend keeping a local copy of it. Do note that C++11 allows for it to be moved constructed (or in fact - optimized even better).

Qt + xapian library

I'm trying to use Xapian library in my Qt-project.
I've just added header:
#include <QtCore/QCoreApplication>
#include <xapian.h>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}
And there are already some mistakes here:
/usr/local/include/xapian/keymaker.h:64: error: a template-id may not appear in
a using-declaration
64: std::vector<std::pair<Xapian::valueno, bool> > slots;
and this one as well:
/usr/local/include/xapian/keymaker.h:77: error: expected primary-expression
before ‘.’ token
77: slots.push_back(std::make_pair(slot, reverse));
I don't know what does it mean. But I guess I should add something into my pro-file. Could you please help me? Thanks.
The problem you run into is that Xapian uses "slots" as identifier, but "slots" is also a define in Qt:
From qobjectdefs.h
# if defined(QT_NO_KEYWORDS)
# define QT_NO_EMIT
# else
# define slots
# define signals protected
# endif
As you include QApplication (and thus qobjectdefs.h) before xapian.h, the preprocessor deletes all occurrences of "slots" from xapian.h.
To avoid this problem, build your project with -DQT_NO_KEYWORDS.
You then have to use "Q_SLOTS" and "Q_SIGNALS" instead of "signals" and "slots" in your Qt Code (which is good practice anyway).

QDomElement::setTagName doesn't seem to work

The code
#include <QtCore>
#include <QtXml/QDomElement>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QDomElement* element = new QDomElement();
element->setTagName("feature");
qDebug() << element->tagName();
return app.exec();
}
prints simply "". However, as far as I can tell from the documentation it should print "feature". In fact
qDebug() << element->isNull();
prints true so something is not being set correctly. Does anyone know what I am doing wrong?
I'm using Qt 4.6.3 on openSUSE Linux 11.2.
You cannot use the default constructor. You need to use QDomDocument::createElement(const QString &tagName). The element needs to be part of a document. You cannot use it "standalone".
Here's what the documentation says for the QDomElement default constructor:
QDomElement::QDomElement ()
Constructs an empty element. Use the QDomDocument::createElement() function to construct elements with content.
By "empty" they mean null.

Resources