0

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?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Aleksey Kontsevich
  • 4,671
  • 4
  • 46
  • 101
  • 1
    Can't reproduce (Linux + Qt5.11.2). `projectsMap`definitely isn't empty? Are the types contained within the `QVariant` instances all registered with the `Qt` meta-type system? – G.M. Oct 12 '18 at 11:31
  • @G.M., yes, not empty: checking this with `qDebug()` Contains QString for key and value. Problem is even `"projects"` key is not created in `"Group"` in ini file. – Aleksey Kontsevich Oct 12 '18 at 12:01
  • @G.M., problem was in `settings->sync()`: above setting store operations performed in destructor and I thought settings destructor should call `sync()` automatically - seems it is not the case, so calling `sync()` explicitly now - works fine! Thanks! – Aleksey Kontsevich Oct 12 '18 at 12:31
  • This question is deficient until a complete test case is provided. What “destructor” do you set the settings in? Destructors aren’t special in any way here, and `QSettings` doesn’t care either. – Kuba hasn't forgotten Monica Oct 12 '18 at 13:10
  • @KubaOber, in my class settings declared as `QPointer settings;` and seems while destroying the object `settings->sync()` is not called. Call it explicitly. – Aleksey Kontsevich Oct 12 '18 at 13:44
  • Comments are not an appropriate way of fixing deficient questions: you’re supposed to edit your question to fix it. Include a complete test case: a `main.cpp` that begins with `#include ` and ends with optional `#include "main.moc"` – Kuba hasn't forgotten Monica Oct 12 '18 at 13:52

1 Answers1

3

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.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • I see, missed that info about `QPointer` now I understand why people using `std::unique_ptr` in Qt applications as `QPointer` is not the analogue. Will change to `std::unique_ptr` to automatically clean up the object. Your way does not works for me as settings object is owned by manager class and shared between many controlled classes. Just need to clear settings object correctly - will use `std::unique_ptr` for this or just `QSettings settings;` as unique_ptr not so convenient as `QPointer`. – Aleksey Kontsevich Oct 13 '18 at 06:59
  • I’m telling you that you should not do this with the settings object! Do not “manage it”! You’re inventing work for yourself that you should not even attempt. Instantiate it every time you want to use it. It was designed to be used that way. And instead of using a pointer, you should store things by value. What’s the purpose of the pointer? There’s none. Only use the pointer of the lifetime of an object differs from the lifetime of the “manager”. In modern C++, most such “managers” should be a simple struct with values, a few of them perhaps wrapped in `optional`. – Kuba hasn't forgotten Monica Oct 13 '18 at 12:22
  • Controlled objects know nothing about settings, do not hold them, access via manager()->setting()-> that is why I need pointer: to share single settings instance between manager and controlled objects. – Aleksey Kontsevich Oct 14 '18 at 13:23
  • The controlled objects should create an instance of `QSettings` whenever they need it. If `setting()` returns something other than a pointer to `QSettings`, i.e. your own class, then that class should create the settings object as needed – temporarily. In fact, you can wrap `QSettings` in your own `Settings` class that the other objects can use; this class would expose settings indirectly via getters/setters, for example. – Kuba hasn't forgotten Monica Oct 15 '18 at 00:52
  • This answer caused me to waste some time trying not to use a `QSettings *`. So what if that's not how it was intended to be used? QThread also wasn't designed to have its thread working code in run(); but this is now a supported usage. `QSettings *pSettings;` works just fine for me. I hate to set up all the parameters each time. If you `new` it, and pass it a parent argument, it'll automatically take care of any memory freeing that needs to happen. – CodeLurker Dec 19 '19 at 07:11
  • I don't think I was quite clear: there's no point to reusing `QSettings`. Just make one when you need it. It won't forget any settings in-between. I don't know what you mean by "I hate to set up all the parameters each time" - the whole point is that you don't need to do that. You can have code like `QSettings settings; if (settings.value(kSomeSettingKey).toBool()) { /* do something here */ }`. Nothing more is needed. As for `kFoo`: it's a reusable constant, belonging in a `.h` file somewhere so you can use it anywhere you need to access the settings, so you won't have bugs due to typos. – Kuba hasn't forgotten Monica Dec 19 '19 at 15:37