Solved static const QString, implicit sharing issue
-
Hi,
I have a very stange bug I would like to understand more about,
Qt Version 5.11.2 (can't upgrade to 5.12 unfortunately because it does not happen with 5.12)
Target OS android.I have a header file that contains a bunch of const static QStrings that are used throught the application.
In my App I have the following line of code:
QString DefaultPath(dataPath );
where dataPath is the static const QString, this line crashes.
However when I do the following
QString DefaultPath(dataPath + "" );
basically forcing a copy, it does not crash.
It also only crashes on my Samsung device, the HUAWEI one works fine.
Also also it only crashes in release mode, debug works fine acrosss the board.I know how to fix this, but I would like to know more about what is going on here.
Anyone any idea?
-
-
static const QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QString("/MPR/"); static const QString dataPath = defaultPath + QString("Data/");
should it be?
-
No, it was just a guess since there are known issues with QStringLiteral in a plugin when the plugin gets unloaded.
Do you get a useful backtrace? I would maybe change it tostatic QString defaultPath() { return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QString("/MPR/"); }
To avoid global statics.
-
@Christian-Ehrlicher well, that fixes the issue as well, and is probably the more reasonable fix, than adding an empty QString to
dataPath
when I use it.Lot's of refactoring to do! x)
Thanks.
-
And it is the only feasible solution. Having non-POD-types as global variables is undefined behavior, as the constructor of your global static might be run anytime (and you don't know when). Therefore its eays to access the data before it is initialized.
Regards
-
@aha_1980
well technically, the only non POD-qualifying trait would be QString not being an intrinsic type - which is enough ;-). Never the less your argument still holds true! -
Actually I'm pretty sure the problem is not so much it being POD or not, but rather that you have dependent initialization.
dataPath
depends ondefaultPath
but C++ does not guarantee you order of initialization of statics. SodataPath
might just be initialized with garbage (i.e. beforedefaultPath
is initialized). Additionally, I thinkQStandardPaths
(I may think wrong) is available only afterQCoreApplication
is up and running. -
@J-Hilk, could you try something for me btw, just out of curiosity:
static struct { const QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QString("/MPR/"); const QString dataPath = defaultPath + QString("Data/"); } strings;
Does that have the same problem?
-
@kshegunov very true,
It's probably for the best, if I'll wrap this all in a propper class at this point.
I centralized all those path for 2 reasons.- I had to change 1 path and boy, was that a pain.
- I wanted to reduze the overall memory consumption of the app.
- Still applies,
- doesn't matter if it's not static but constructed at runtime.
legacy code - there's always something x)
Does that have the same problem?
I'll test it.
-
@kshegunov said in static const QString, implicit sharing issue:
@J-Hilk, could you try something for me btw, just out of curiosity:
static struct { const QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QString("/MPR/"); const QString dataPath = defaultPath + QString("Data/"); } strings;
Does that have the same problem?
It does not! Works fine with the static struct.
-
Indeed, so you have your answer then. One note: this "hack" is going to work only with dynamic linking. If you go to static you're going to run into the same stuff, and not in a good way ... ;) Static init is per-module, so having only one module means at that struct's init
QStandardPaths::writableLocation
's statics may just be initialized sometime in the future. -
@kshegunov I'm learning something new every day :D
However, I'll stick to the proper class implementation and inherit from that simple class where the standardpaths are needed. It's the way, where the least refractoring is needed. I'm kind of on a deadline so close to christmas x)
Thanks all for bringing light to my dark place, where I spend the last couple of days figuring this out, and I'm cutting it close as it is.
-
@J.Hilk said in static const QString, implicit sharing issue:
@kshegunov I'm learning something new every day :D
Don't we all ... :)
However, I'll stick to the proper class implementation and inherit from that simple class where the standardpaths are needed.
Probably the best and most reliable solution.
I'm kind of on a deadline so close to christmas x)
I hear you brother! I have to deliver on the 2nd of January.