Results 1 to 17 of 17

Thread: QString::append() weirdness

  1. #1
    Join Date
    Apr 2009
    Location
    Italy
    Posts
    70
    Thanks
    23
    Thanked 15 Times in 11 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default QString::append() weirdness

    Hello,
    does anybody know why in the following code 's' contains trash upon creation, but becomes valid after creating another QString?


    Qt Code:
    1. #include <QApplication>
    2. #include <QDebug>
    3.  
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication app(argc, argv);
    7.  
    8. const QString& s = QString("hello").append("world");
    9. qDebug() << s; // s is invalid here (seen in the debugger)
    10.  
    11. QString t = QString("hello").append("world");
    12. qDebug() << s; // s is ok (??????)
    13.  
    14. return 0;
    15. }
    To copy to clipboard, switch view to plain text mode 
    Qt 4.7
    VS 2008 SP2
    Vista

  2. #2
    Join Date
    Apr 2010
    Posts
    769
    Thanks
    1
    Thanked 94 Times in 86 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QString::append() weirdness

    s is a reference. You're trying to initialize it with a temporary variable. After the initialization, the temporary no longer exists and s has nothing to refer to.

    It probably appears to contain something after the next initialization - which uses actual variables instead of references - because the memory region s was pointing at now just happens to contain the contents of t. Or because some other memory rearrangement takes place that makes it appear valid.

    In short, you're not using references correctly here. References have to refer to something; they don't contain any values of their own.

    Get rid of the ampersand and everything will work correctly, I'd bet.

  3. #3
    Join Date
    Apr 2009
    Location
    Italy
    Posts
    70
    Thanks
    23
    Thanked 15 Times in 11 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QString::append() weirdness

    AFAIK, binding a temporary to a const reference is perfectly legal in C++, I am doing that all the time.

    I guess my problem has to do with the infamous "implicit sharing" of Qt data types. I think in this case it is breaking the C++ rules in a very dangerous way.

  4. #4
    Join Date
    May 2010
    Location
    Romania
    Posts
    1,021
    Thanks
    62
    Thanked 260 Times in 246 Posts
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: QString::append() weirdness

    Quote Originally Posted by mattc View Post
    AFAIK, binding a temporary to a const reference is perfectly legal in C++, I am doing that all the time...
    I strongly suggest you stop doing that, assign a temporary value to a reference is a source of bugs (somewhat simmilar with using pointers after the delete call)

  5. #5
    Join Date
    Jan 2008
    Location
    Poland
    Posts
    687
    Thanks
    4
    Thanked 140 Times in 132 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QString::append() weirdness

    Quote Originally Posted by mattc View Post
    AFAIK, binding a temporary to a const reference is perfectly legal in C++, I am doing that all the time.

    I guess my problem has to do with the infamous "implicit sharing" of Qt data types. I think in this case it is breaking the C++ rules in a very dangerous way.
    But did you checked that using non-Qt non-implicit shared class will give you result you expect?
    I didn't know so I checked (it is not that hard) and I think that you're wrong.

    Check this code:
    Qt Code:
    1. #include <iostream>
    2.  
    3. class List
    4. {
    5. public:
    6. List() : head(0) {}
    7. ~List();
    8. char operator[](int index) const;
    9. List &prepend(char item);
    10.  
    11. private:
    12. struct Elem {
    13. char data;
    14. Elem *next;
    15. };
    16. Elem *head;
    17. };
    18.  
    19. List::~List()
    20. {
    21. for (Elem *e = head; e != 0;) {
    22. Elem *d = e;
    23. e = e->next;
    24. delete d;
    25. }
    26. }
    27.  
    28. char List::operator[](int index) const
    29. {
    30. Elem *tmp = head;
    31. for (int i = 0; i < index; ++i) {
    32. tmp = tmp->next;
    33. }
    34. return tmp->data;
    35. }
    36.  
    37. List &List::prepend(char item)
    38. {
    39. Elem *e = new Elem;
    40. e->data = item;
    41. e->next = head;
    42. head = e;
    43. return *this;
    44. }
    45.  
    46. int main()
    47. {
    48. const List &l = List().prepend('a');
    49. std::cout << l[0] << std::endl;
    50.  
    51. List s;
    52. const List &t = s.prepend('b');
    53. std::cout << t[0] << std::endl;
    54.  
    55. return 0;
    56. }
    To copy to clipboard, switch view to plain text mode 
    There is no Qt class nor implicit sharing. It is simple list implementation, with prepend() method (the same idea as in append, but in my case prepend was easier to implement). What output you expect?
    I would like to be a "Guru"

    Useful hints (try them before asking):
    1. Use Qt Assistant
    2. Search the forum

    If you haven't found solution yet then create new topic with smart question.

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QString::append() weirdness

    Quote Originally Posted by mattc View Post
    AFAIK, binding a temporary to a const reference is perfectly legal in C++, I am doing that all the time.
    Are you sure your reference lives longer than the temporary variable? I strongely doubt that.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  7. #7
    Join Date
    May 2010
    Location
    Romania
    Posts
    1,021
    Thanks
    62
    Thanked 260 Times in 246 Posts
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: QString::append() weirdness

    Maybe the 'infamous "implicit sharing" ' makes some of the code to just "look like" it "works", but it still a bad practice and can anytime give you the world-famous "Segmentation Fault" error.

    And another issue is that you can't modify a variable by using a const reference to it (even if the variable itself isn't const)

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QString::append() weirdness

    Quote Originally Posted by mattc View Post
    AFAIK, binding a temporary to a const reference is perfectly legal in C++, I am doing that all the time.
    It is really easier to make a test than to ponder about things one "thinks" he knows. And so I made a test...

    Here is our test subject:

    Qt Code:
    1. #include <QtDebug>
    2.  
    3. class TestSubject {
    4. public:
    5. TestSubject() {
    6. qDebug() << Q_FUNC_INFO;
    7. }
    8. ~TestSubject() {
    9. qDebug() << Q_FUNC_INFO;
    10. }
    11. TestSubject& operator=(const TestSubject &other) {
    12. qDebug() << Q_FUNC_INFO;
    13. return *this;
    14. }
    15.  
    16. TestSubject(const TestSubject &other) {
    17. qDebug() << Q_FUNC_INFO;
    18. }
    19. };
    To copy to clipboard, switch view to plain text mode 

    Here is our test:
    Qt Code:
    1. const TestSubject &testFun() {
    2. return TestSubject();
    3. }
    4.  
    5. int main() {
    6. const TestSubject &obj = testFun();
    7. qDebug() << "After testFun call";
    8. return 0;
    9. }
    To copy to clipboard, switch view to plain text mode 

    Here is the compilation log on gcc:
    Quote Originally Posted by log
    main.cpp: In function ‘const TestSubject& testFun()’:
    main.cpp:20: warning: returning reference to temporary
    And here is the output:
    text Code:
    1. TestSubject::TestSubject()
    2. TestSubject::~TestSubject()
    3. After testFun call
    To copy to clipboard, switch view to plain text mode 
    meaning that there is no copy upon returning a const reference hence when the temporary object is deleted (which happens before the qDebug() line in main()) the const reference points to an invalid object. Regardless if you use implicit sharing or not as it has completely nothing to do with the situation.

    Conclusion: binding a temporary to a const reference is not legal in C++.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #9
    Join Date
    Apr 2009
    Location
    Italy
    Posts
    70
    Thanks
    23
    Thanked 15 Times in 11 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QString::append() weirdness

    Oops, it was not my intention to start a flame-like thread.

    I found this page by Herb Sutter about the "lifetime of const references bound to temp objects":
    http://herbsutter.com/2008/01/01/got...portant-const/

    @Wisota: your code is actually returning (not just binding) a reference to a temporary object, and that is invalid.

    @Faldzip: you are right, your code has the same problem as the one I posted, and there is no implicit sharing involved. Still, it is not clear to me why it does not work. I see the destructor being called after the call to your prepend(), but I see no reason for that. I believe the list should happily bind to the const reference and live longer.

    Thansk everybody, now I see the problem is unrelated to Qt.

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QString::append() weirdness

    Quote Originally Posted by mattc View Post
    Oops, it was not my intention to start a flame-like thread.

    I found this page by Herb Sutter about the "lifetime of const references bound to temp objects":
    http://herbsutter.com/2008/01/01/got...portant-const/

    @Wisota: your code is actually returning (not just binding) a reference to a temporary object, and that is invalid.
    Correct me if I'm wrong but in the blog you mention the function call actually returns a perfectly good copy of the temporary object. According to me this is a different situation than the one in your code. The scope of the two situations is different.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  11. #11
    Join Date
    Apr 2009
    Location
    Italy
    Posts
    70
    Thanks
    23
    Thanked 15 Times in 11 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QString::append() weirdness

    Reading the blog I understand the scope is the same, but I am not sure, so I posted the question on comp.lang.c++ (for anyone interested):

    http://groups.google.com/group/comp....648e41ec70ee5#

  12. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QString::append() weirdness

    Just a side note - if in my example I change the function signature to return a copy of an object, then indeed the destructor of the object gets delayed. The same happens here:

    Qt Code:
    1. int main() {
    2. const TestSubject &obj = TestSubject();
    3. qDebug() << "After testFun call";
    4. return 0;
    5. }
    To copy to clipboard, switch view to plain text mode 

    Your situation seems to be somehow different but I fail to see where. Maybe because your temporary object is not const.

    Edit: yes, that's exactly the case:
    Qt Code:
    1. TestSubject& TestSubject::x() { return *this; }
    2.  
    3. int main() {
    4. const TestSubject &obj = TestSubject().x();
    5. qDebug() << "After testFun call";
    6. return 0;
    7. }
    To copy to clipboard, switch view to plain text mode 

    gives again:
    text Code:
    1. TestSubject::TestSubject()
    2. TestSubject::~TestSubject()
    3. After testFun call
    To copy to clipboard, switch view to plain text mode 
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  13. The following user says thank you to wysota for this useful post:

    mattc (17th October 2010)

  14. #13
    Join Date
    Apr 2009
    Location
    Italy
    Posts
    70
    Thanks
    23
    Thanked 15 Times in 11 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QString::append() weirdness

    Thank you for your efforts Wysota.

    It turns out the code does not work "because the standard says so". In other words, while this code is ok:

    Qt Code:
    1. // bind a temporary *expression* to a const reference
    2. const QString& s = QString("hello");
    To copy to clipboard, switch view to plain text mode 

    this one leaves a dangling reference:

    Qt Code:
    1. // bind a temporary *object* to a const reference
    2. const QString& s = QString("hello").append("");
    To copy to clipboard, switch view to plain text mode 

    I believe that from a purely "technical" point of view there is nothing wrong with the second snippet (a compiler could easily generate working code), but in fact it is not supposed to work.

  15. #14
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QString::append() weirdness

    Thankfully with the "imfamous implicit sharing" Qt offers you can happily do this:
    Qt Code:
    1. QString s = QString("hello").append("");
    To copy to clipboard, switch view to plain text mode 
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  16. #15
    Join Date
    Apr 2009
    Location
    Italy
    Posts
    70
    Thanks
    23
    Thanked 15 Times in 11 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QString::append() weirdness

    LOL

    You know, I am a bit nervous about "implicit sharing" since I reported this bug (read: feature):
    http://bugreports.qt.nokia.com/browse/QTBUG-12941

    In short, though QLinkedList offers the same "iteration" interface of a std::list (begin(), end()), the behaviour of the iterators it provides is not standard conforming.

    For example, the standard says that a std::list::end() iterator should remain constant through the lifetime of a list. But calling QLinkedList::clear() can in fact change the value returned by QLinkedList::end().

    So, when in my code I blindly replaced some std::lists with QLinkedLists I got crashes everywhere.

    Nothing to pull your hair about, of course, but still annoying... and guess who's to blame for that? :-)

  17. #16
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QString::append() weirdness

    I fail to see how this can make you nervous about implicit sharing itself. As long as you don't call clear() on the list the behaviour will be as you expect it. And the behaviour of clear() is not related to implicit sharing itself but rather to limiting memory usage of empty lists (which happens to be implemented using implicit sharing).
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  18. #17
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Thanked 268 Times in 268 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Wiki edits
    20

    Default Re: QString::append() weirdness

    Besides that, changing the items while iterating over them is not safe.

Similar Threads

  1. [SOLVED] quint16 weirdness
    By pdoria in forum Qt Programming
    Replies: 4
    Last Post: 15th October 2009, 00:09
  2. Cannot append to QFile using QIODevice::Append
    By philwinder in forum Qt Programming
    Replies: 4
    Last Post: 17th November 2008, 09:09
  3. Need help. can't append chars in QString
    By AcerExtensa in forum Qt Programming
    Replies: 6
    Last Post: 12th June 2008, 10:57
  4. Memory leak weirdness
    By Darhuuk in forum General Programming
    Replies: 10
    Last Post: 10th January 2008, 18:51
  5. QSplashScreen Weirdness
    By mclark in forum Qt Programming
    Replies: 11
    Last Post: 19th November 2007, 06:49

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.