I am building a JSON-object with Qt and convert it to a QString using QJson. This (normally) works fine and it does in this case but in the destructor of my Qt data structure, it crashes with an Access Violation. The Object is built fine, it is sent over my network connection and after the function ends, my application crashes.
My code looks like this:
void bar()
{
QVariantMap data;
data.insert("Id", 1);
QList<QVariant> list; //QVariantList
for (QMap<...>:ConstIterator ... ) //Loop through a Map
{
QMap<QString, QVariant> singleEntry; //QVariantMap
singleEntry.insert("LocalId", it.value());
QList<QVariant> entryList; //QVariantList
for (...) //Loop through another structure
{
entryList.append("foo");
}
singleEntry.insert("List", entryList);
list.append(singleEntry);
}
data.insert("Entries", list);
QJson::Serializer.serialize(data); // Works fine
} // Crash here
If I remove the inner loop, which builds up entryList, everything works fine. It seems that the destructor of data cannot delete the contents but I have no idea, why. The whole data structure seems to be fine while serializing it (and I hope that QJson does not change anything in the given data) but it cannot be cleaned up..
Best Regards,
Tobias
As Raiv said this can happen when mixing debug and release dlls, but in my oppinion this can also happen if the application and the Qt DLL's use different CRT libraries. Some people say that when they recompiled Qt on their machines the problem dissapears and I think this is because the CRT dlls after Qt rebuild are the same as the app's. Try to set the Runtime Library option in C/C++ Code Generation is set to Multi-threaded Debug DLL (/MDd) or Multi-threaded DLL (/MD) respectively for Debug and Release. Some Qt types as QVariantMap, QVariantList, QModelIndexList are probably allocated with /MD (in Qt's dll) and when they are deallocated with /MT (in the app) I think this causes the crash. This can also fix the crash on QString::toStdWString(). In order for this to link maybe the Ignore All Default Libraries should be set to No and Ignore Specific Library should not mention crt dlls used by Qt.
I got a little workaround, which fits my needs. I have still no idea, why this crash happens, but I know, which should be the problem.
I tried to build up a static structure like this:
QVariantMap
QVariantList
QVariantMap
QVariantList
and it crashes. If I remove the QVariantList at the bottom and add QVariantMap or anything else instead, it is working fine. I think this is a problem with the nesting level in this case.
I have now just joined my list as a comma-seperated QString and then it works fine.
If anyone of you has an idea, why the crash in destructing such a nested struct (another information: doesnt matter if a allocate the QVariants in heap and delete them myself or stack) and how to fix it, please let me know.
Related
Why it was possible in Qt 5.2 and previously and stored data in following format:
key=#Variant(\0\0\0\b\0\0\0)
but have problem now in Qt 5.11?! Following code
QVariantMap projectsMap;
for (auto project : projects)
projectsMap.insert(key, value);
settings->setValue("Group/projects", projectsMap);
executes correctly however stores nothing to ini file.
qRegisterMetaTypeStreamOperators<QVariantMap>("QVariantMap");
does not help as well. How to store this, what is the problem here?
Don’t store QSettings: it’s not meant to be used that way. You should use a fresh instance of QSettings every time you change the settings. Your destructor should look as follows:
MyClass::~MyClass() {
QSettings s;
s.setValue(kFoo, this->m_bar);
…
}
QSettings is an ephemeral handle to the settings system, its instantiation is cheap. You leak it because QPointer does not destroy anything: it’s not an owning pointer.
I have to create a SQLite database using System.Data.SQLite and using C++/CLI but I run into problems. Unfortunately, using C# is not an option, if it was then there is no problem. (Please don't advise me not to use C++/CLI, it is not an option in this project.)
In C# the following code works without any problem.
using System.Data.SQLite;
void CreateDb(String file)
{
SQLiteConnection.CreateFile(file);
}
The equivalent code in C++/CLI is not without its problems.
using namespace System::Data::SQLite;
void CreateDb(System::String ^file)
{
SQLiteConnection::CreateFile(file); // error C2039
}
The exact error txt for C2039 is:
// error C2039: 'CreateFileA' : is not a member of 'System::Data::SQLite::SQLiteConnection'
If I take a closer look at the definition of CreateFile I get the following choice
#define CreateFile CreateFileW - c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\WinBase.h(9292)
#define CreateFile CreateFileA - c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\WinBase.h(9294)
Which leads to the following lines in WinBase.h
#ifdef UNICODE
#define CreateFile CreateFileW
#else
#define CreateFile CreateFileA
#endif // !UNICODE
The Microsoft SDK is muddling with exact the name that I need and SQLite does not provide me with CreateFile[AW] versions.
So I tried this before the code calling SQLiteConnection.CreateFile(file) and I do this isolated so that other code is affected by it.
#ifdef CreateFile
#undef CreateFile
#endif
It solves my problem (for now) but how safe is this?
Is there a better way of solving this problem?
Your advise is much appreciated.
The #undef is how I've always handled this.
how safe is this?
This is safe.
You may have this problem again if you have other name collisions. The compile errors resulting from such a name collision are easy to diagnose, now that you know what you're looking for, so it will be easy to add additional #undef directives if needed.
If you need to call the Win32 CreateFile, you will need to type CreateFileA or CreateFileW explicitly, but that's not a big hassle.
Is there a better way of solving this problem?
Yes, but it's not always possible.
The better way is to not #include <Windows.h> in the files where you use SQLite. This avoids the problem entirely. However, it's not always possible to organize your program like this, so #undef is usually the solution.
(This next paragraph doesn't apply to your scenario with SQLite: You're using the managed version, so there's no headers. This next bit applies to C++ libraries that include library headers. I'm including it for completeness in case someone is writing plain C++.)
One other thing to watch out for here is #include-ing the Windows headers before library headers. In that case, the class definition itself will have CreateFile renamed to CreateFileA. If you use #undef with that, you'll get the opposite error from what you showed. You can leave the #define in place, which will sometimes end up working, but this is rather fragile, so I would avoid this scenario.
(I ran into this once with MFC headers in a C++ application: The changed method name ended up everywhere, even Intellisense showed the name as ending in "A". It worked anyway because the vTable was initialized inside the MFC DLL, and so all that mattered in the calling application was that the vTable pointed at the right method, which it was.)
What is an optimal and an appropriate way to save the state of a Qt GUI so I get the same state I had back when I closed the application ?
By state I mean : current indexes (for combo box ...), color palette, widgets positions... right before closing the application
You can use the QSettings class.
Simple use of QSettings class (code inspired from Qt's documentation):
In the main-window of your application code member functions that saves and restore the settings:
void MainWindow::writeSettings()
{
QSettings settings("reaffer Soft", "reafferApp");
settings.beginGroup("MainWindow");
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void MainWindow::readSettings()
{
QSettings settings("reaffer Soft", "reafferApp");
settings.beginGroup("MainWindow");
resize(settings.value("size", QSize(400, 400)).toSize());
move(settings.value("pos", QPoint(200, 200)).toPoint());
settings.endGroup();
}
Call those 2 functions from the MainWindow constructor and from the closeEvent override, like this:
MainWindow::MainWindow()
{
// code from constructor
//...
readSettings();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
//optional check if the user really want to quit
// and/or if the user want to save settings
writeSettings();
event->accept();
}
The direct answer requires specific elaborated design for your code and not really a short Qt question or even the question specific to Qt. That is about C++ which is not the VM-based language that assists with serializing the state of program code to data. Having all objects serializable we can then attempt to apply certain C++/Qt classes/techniques.
This task is much easier to accomplish with languages like Java, though. And with C++/Qt you have to routinely make serialize-able / serialize / restore everything that is running in your code and still no guarantee that works as long as the context is not fully captured. This task is not easy for sure and makes sense only in specific application.
The most you can get directly from Qt is to save/restore QMainWindow and other independent widgets geometry (position/size):
saveGeometry
restoreGeometry
... and that solution is still somewhat incomplete or you may/not use QSettings for the storage.
I use QSettings for this. With routines similar to Zlatomir's.
For each window I have in the project I use a different section in QSettings and have readSettings() and writeSettings() in the source for each window.
Anything on the form that I want to persist I have to explicitly save and recall. In the case of a QComboBox it would be something like:
QSettings settings("Organisation", "MySoftware");
settings.beginGroup("WindowNumberTwo");
settings.setValue("ComboIndex", combobox->currentIndex());
// save more values here
// ...
settings.endGroup();
I don't know of a built in way to persist your window states - it has to be don't value by value.
I'm trying to create a dynamic array of pointers to structure objects. I have done this before, but never really understood it, so I'm lost now that it's failing.
My code is:
struct object {
char* alias;
char* mapInfo;
char* binaryData;
};
class ATP
{
public:
ATP();
std::vector<std::shared_ptr<object>> objects;
};
This compiles fine, but when I try to run it it says
"ATPEditor.exe has stopped working. A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available."
I'm not trying to use anything like a push_back yet, I'm just trying to create the array.
Does anyone know why this is failing? Or if there is somewhere else I might have made a mistake?
EDIT: When copying the rest of my code into this window, I noticed that I had mistyped the constructor. Once I fixed it the problem went away. Thanks.
I noticed that the Qt documentation is not very verbose on some of the aspects of the translations. I was fooling around with it trying to figure out their behaviour using trial & error. The ultimate goal is to get the translation changed on runtime but I am very confused as to what extent the QTranslator object can be re-used.
Consider this (where 'a' is the main instance of the application):
QTranslator translator;
translator.load("mytranslation_cz");
a.installTranslation(&translator);
(...)
a.removeTranslation(&translator)
Now the translator was removed from the application but what happened to the translator object?
In my tests when above code was followed by this again
translator.load("mytranslation_fr");
a.installTranslation(&translator);
it did not do anything in main() and it crashed the application when called from one of the widgets (using pointer to main app).
Therefore I am suspecting that I would need to create one QTranslator object per translation I want to load in the application and that I cannot reuse the QTranslator object. Am I right in this assumption?
And as a side question. Assuming the QTranslator object is untouched by the removeTranslation(), is it possible to simply install it later again like this?
QTranslator translator;
QTranslator translator1;
translator.load("mytranslation_cz");
translator1.load("mytranslation_fr");
a.installTranslation(&translator);
(...)
a.removeTranslation(&translator);
a.installTranslation(&translator1);
(...)
a.removeTranslation(&translator1);
a.installTranslation(&trasnlator); //Will this work?
Thanks for any clarification as I am somewhat confused as to what happens to the QTranslation objects when installing and removing translations from the application and especially if the QTranslation object can be reused for multiple translations somehow on runtime?
QTranslator::load basically in simple sense can be considered as a function that opens a given .qm file, reads in all the translated values and loads it in for a specific language.
Now in general operation you would not want to reuse this for many languages as by "reusing" (even if its allowed) your adding the overhead of parsing this given .qm file for every language every time you switch your UI language, which is just basically an overhead you don't need.
Your assumption of creating a QTranslator for each language is correct. As for your side question, Yes you can also re-use it. Thats the benefit of having individual QTranslator objects per translation. Just call qApp->removeTranslator() with the current translation and then qApp->installTranslator() with the new one. This way you are reusing the loaded translations as and when you please.
The way we structure this is by sub-classing QApplication and adding 2 functions
void Application::CreateTranslators() {
// translators_ is a QMap<QString, QTranslator*>
if (!translators_.isEmpty())
return;
QStringList languages;
languages << "en" << "ar" << "zh";
foreach(QString language, languages) {
QTranslator* translator = new QTranslator(instance());
translator->load(language);
translators_.insert(language, translator);
}
}
Now this function is called at the very start of the application.
2nd function is as following
void Application::SwitchLanguage(QString language) {
// current_translator_ is a QTranslator*
if (current_translator_)
removeTranslator(current_translator_);
current_translator_ = translators_.value(language, nullptr);
if (current_translator_)
installTranslator(current_translator_);
}
That's it. Using the second function you can switch your language at run-time as you please.
Couple things you'll also need to be aware of is changing QTranslator at run-time will update all translations from your .ui file strings marked as translatable automatically, however those set from code will not be. To get that you will have to override QWidget::changeEvent() and then check if the event is of type QEvent::LanguageChange and then set the required strings for that QWidget accordingly (Don't forget the tr() while doing so)