I need to copy a QString every time it is used?



  • Perhaps I am missing something basic about references/pointer translation but please explain to me why the following code doesn't work... (the QDir overload I am using is QDir(QString&)

    @
    // from header file
    class A
    {
    ...
    public:
    void assignBaseDir();
    private:
    QString mBaseFolder;
    QDir
    mBaseDir
    }

    // from cpp file:
    A::assignBaseDir()
    {
    mBaseDir = new QDir(*mBaseFolder); // throws a memory access violation!
    }
    @

    EDIT: FYI: It might help to know that mBaseFolder is initialized with a QString allocated on the stack in the main executable while the A class is located in a separate dll. If I copy the QString to a new QString in A's constructor it works fine. However, I would still like to understand the logic behind this.


  • Moderators

    Hi,

    Did you initiliase mBaseFolder using new operator ?
    But why do you want to ? QString uses "implicit sharing":http://qt-project.org/doc/qt-5/qstring.html#details



  • well that seems odd considering what "fixed" the problem. Please see my "EDIT: FYI:" in the original post.



  • There is nothing assigned to mBaseFolder. It has invalid address. You need to change QString *mBaseFollder to QString mBaseFolder.



  • No... that is not true. mBaseFolder is a pointer that is assigned in the constructor. If you read my edit above it says "It might help to know that mBaseFolder is initialized with a QString allocated on the stack in the main executable..."

    and FYI: yes... I do convert from the QString to the pointer using the address operator.



  • Is your constructor like this:

    @
    {
    QString myString = "bla";
    mBaseFolder = &myString;
    }
    @

    ??



  • Hi,

    It would help to see more of your code. Are you sure the QString you take the adress from to pass it to your A class is still alive when you use it?



  • Ok.... here you go (class names changed but this is essentially the code):

    @
    // from main()
    ...
    QString appPath(QApplication::applicationDirPath());
    A aInstance(&appPath);
    aInstance.assignBaseDir();
    @

    @
    // A class initializer
    A::A(QString* basePath) :
    mBaseDir(NULL),
    mBaseFolder(basePath)
    {
    }
    @

    Please keep in mind that A is in a dll while main is in the executable. Is it simply that the dll does not have access to the executable's stack space?


  • Lifetime Qt Champion

    Hi,

    There's no need to allocate QStrings on the heap. Just use const references when passing it around, it will only get copied once you modify it.

    @
    {
    QString myString = "bla";
    mBaseFolder = &myString;
    } <- myString is destroyed, mBaseFolder becomes a dangling pointer.
    @

    Look at p3c0's link, it explains everything nicely



  • [quote]
    @
    // from main()
    ...
    QString appPath(QApplication::applicationDirPath());
    A aInstance(&appPath);
    aInstance.assignBaseDir();
    @

    [/quote]

    In line 3 you create a QString-Object on Stack. You pass a pointer to that object to your other function. Somewhere after line "5" I assume there is a "}" which you did not show. When that "}" comes, your stack-objects, including the QString are getting destroyed. When you later access the QStrings pointer, the memory is no longer valid.

    Sorry -- this is kind of a beginners mistake :-/ Just do it as said before -- in your class A you should use "QString" rather than "QString *".

    Best Regards,
    Tobias



  • [quote author="primem0ver" date="1410684255"]Ok.... here you go Is it simply that the dll does not have access to the executable's stack space?[/quote]

    No one has access to each others stack space... Stack-Objects are destroyed when leaving context...

    In General: dont use pointers to objects on stack!!



  • [quote author="topse" date="1410696530"][quote]
    @
    // from main()
    ...
    QString appPath(QApplication::applicationDirPath());
    A aInstance(&appPath);
    aInstance.assignBaseDir();
    @

    [/quote]

    In line 3 you create a QString-Object on Stack. You pass a pointer to that object to your other function. Somewhere after line "5" I assume there is a "}" which you did not show. When that "}" comes, your stack-objects, including the QString are getting destroyed. When you later access the QStrings pointer, the memory is no longer valid.

    Sorry -- this is kind of a beginners mistake :-/ Just do it as said before -- in your class A you should use "QString" rather than "QString *".

    Best Regards,
    Tobias
    [/quote]

    Yes... I am aware that stack space is deallocated for temporary variables in braces when the braces are left. That isn't the issue because the code with the problem is not in a block inside the main method. Don't forget that the the stack space for the main method is not deallocated until the just before the program exits (because the closing brace is at the end of the program).

    I think your second suggestion is the actual problem. Also SGaist's probably applies as well. Thanks!

    Edit: Actually after reading through the implicit sharing for a deeper understanding of how it works and looking back at SGaists suggestion... if I am understanding the article correctly his suggestion isn't quite right either because as I said, the original object does not get destroyed until AFTER the main loop is exited... the '}'/closing brace containing the code isn't exited until then... am I missing something?



  • Here is where I get confused (even after reading the article)

    [quote author="SGaist" date="1410691278"]Hi,

    There's no need to allocate QStrings on the heap. Just use const references when passing it around, it will only get copied once you modify it.

    @
    {
    QString myString = "bla";
    mBaseFolder = &myString;
    } <- myString is destroyed, mBaseFolder becomes a dangling pointer.
    @
    [/quote]

    what would happen if the above code was a function that actually returned myString? (And mBaseFolder was the variable that received it?) Would it still be destroyed? Why or why not? If it is destroyed then allocating QStrings on the heap IS necessary.



  • You really should make up your basics about memory management in C++. Or better: use JAVA, there you wont have those problems.

    Again: myString is an Object on Stack. mBaseFolder stores an address to a memory area on stack. This memory area gets invalid in the moment of "}". Ergo: mBaseFolder points to an invalid address.

    And yes: you should allocate any object on heap, if you want to store pointers. And yes: in Qt you normally dont need to use pointers.

    Please just do what we said:

    @
    class A
    {
    private:
    QString _myString;
    public:
    void setMyString(const QString &newValue)
    {
    _myString = newValue;
    }
    }
    @

    I really dont know how we can help more. My feeling your is, that your problem concern generally C++ and Memory Management. Its nothing Qt-specific.

    Best Regards,
    Tobias


  • Lifetime Qt Champion

    [quote author="topse" date="1410710884"]
    snip
    And yes: you should allocate any object on heap, if you want to store pointers. And yes: in Qt you normally dont need to use pointers.
    snip again
    [/quote]

    That last yes is not true, you don't need to allocate on the heap Qt's container classes, QString/QByteArray and some other classes (see the documentation for implicit sharing) but for the rest common C++ rules applies, even more for QObject derived class since you can't copy them.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.