Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Odd file name error



  • I am using QFileDialog to get the file name from the user. When I get this I need to pass a cString to my library.

    QString fileName;
    if (dialog.exec()) {
        fileName = dialog.selectedFiles().first();
    } else {
        return;
    }
    qDebug() << fileName;
    char *cFilename = fileName.toUtf8().data();
    //cFilename = "/Users/aethenorn/testImages/Untitled.jpg";
    this->smugHandle = smuglib_create_smug(cFilename);
    

    I get an error from my library code because it cannot open the file for reading. The file name is sent to console exactly as I expect.
    If I use the hardcoded filename I can open the file for reading.

    So what am I doing wrong extracting the cString filename from the qString filename?

    Thanks in advance for any help.


  • Lifetime Qt Champion

    @aethelnorn which platform is that?



  • @aha_1980 Oooops, I'm getting senile. It is MacOS 10.14, Mojave. Latest download and install of Qt (2 days ago).


  • Lifetime Qt Champion

    @aethelnorn well, you assign the pointer to a temporary value to your cFilename. Is it possible that the value is already no longer valid when you pass it to the lib?


  • Qt Champions 2017

    It could be simple path issue? Can u print filename and see if complete path is coming. I think it gives you only filename.



  • @aha_1980 No, the temp pointer is used immediately in the call to the library. The code above is an exact snippet from a functionalists in my windows class.


  • Lifetime Qt Champion

    @aethelnorn and have you verified your assumption?



  • @aethelnorn Good thought, but I am printing out the filename in the qDebug() and that looks good to me. In fact, I copy/pasted the hardcoded value from the console.



  • @aha_1980 Hmmm. Only by uncommenting the following line and assuming the behaviour of the the two points is the same. I will go and follow in the debugger.


  • Lifetime Qt Champion

    @aethelnorn you print filename, but not cFilename...



  • @aha_1980 Good point......


  • Lifetime Qt Champion

    Hi,

    @aethelnorn said in Odd file name error:

    char *cFilename = fileName.toUtf8().data();

    data returns as point to the internal data of the temporary QByteArray returned by toUtf8.

    The correct way to do that would be:

    QByteArray utf8Filename = fileName.toUtf8();
    char *cFilename = utf8Filename.data();
    

    or

    QByteArray utf8Filename = fileName.toUtf8();
    this->smugHandle = smuglib_create_smug(utf8Filename.data());
    


  • @SGaist said in Odd file name error:

    QByteArray utf8Filename = fileName.toUtf8();
    char *cFilename = utf8Filename.data();

    Thanks, Yeah!! That did it. I was beginning to think that I was going mad. I was following through in the debugger as suggested, and sometimes as I stepped though the const char* cFilename went null, other times it didn't.

    "data returns as point to the internal data of the temporary QByteArray returned by toUtf8"

    Does that mean that there is some kind of memory cleanup going on? Sometimes it worked, sometimes it didn't. I still get blindsided by this in swift occasionally - but that use ARC (automated reference counting) which is aggressive but seemingly asynchronous as well. I did not think memory management was a thing in C++ last time I coded in it (but that was a looooong time ago.

    Or do you mean that the temporary QByteArray was allocated on the stack and later overwritten. If so how does assigning it to a local (stack) variable stop this?

    Ah well, I seems to work now (but I have only tried it three or four times).


  • Lifetime Qt Champion

    @aethelnorn please read http://doc.qt.io/qt-5/qbytearray.html#data

    it says, the pointer remains valid, until the QBA is destroyed. and thats the point - you cannot know, because the QBA as the result of toUtf8() is temporary. you dont hold a reference to it, so the compiler is allowed to destroy it in the following line.

    With @SGaist's way you extend the lifetime by explicitely storing the QBA.

    Regards


  • Lifetime Qt Champion

    It's a question of scope.

    Usual scopes:

    void myFunc()
    {
        int myVar;
        {
            int myVar2;
        } // << myVar2 ceases to exist here
    } // << myVar ceases to exist here
    

    Now in the case that interests us at the moment:

    void myFunc2()
    {
        QString fileName = "MyFile.txt";
        char *utf8Filename = fileName.toUtf8().data(); // the scope of the QByteArray returned by toUtf8 is this line
        // << here the value returned by toUtf8() already ceased to exist
    } // fileName and utf8Filename cease to exist here
    


  • @SGaist, @aha_1980 Thank you for that explanation. Obviously my sojourn in java-land has made me careless and lazy ;-). It is a lesson I need to learn if I am going to do significant C/C++ programming. 'Always keep a reference to intermediate results' might be the sort of thing.

    In Java the thing returned by QBA.data() would be its own object and the reference on the stack would make it ineligible for memory-recycling.

    The basics of the app are working, so now I need to test it against multiple platforms. If the results are encouraging then I think Qt is a winner and I will be delving deeper into the language/compiler/class library.

    Thanks again for your help.


Log in to reply