Results 1 to 10 of 10

Thread: Disturbing: const QString &

  1. #1
    Join Date
    Feb 2007
    Location
    Philadelphia, USA
    Posts
    255
    Thanks
    43
    Thanked 21 Times in 21 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Disturbing: const QString &

    I recently found a bug in one of my programs... and it's disturbing to me, so I'd like some comments.

    Suppose I have a function which takes QString as an argument, and I don't change the value of the argument in the function, so I set it as const (is that what const means by the way?... that the function is not allowed to change the value of it?).

    But the function happened to be recursive, and it called itself with another value of the parameter. This caused UNEXPECTED BEHAVIOR! I can't describe exactly what happens, but the values changed right in the middle of the function!

    Qt Code:
    1. void myfunction(const QString &val) {
    2. ...
    3. QString val2=...;
    4. ...
    5. myfunction(val2);
    6. [Here's where val changed!]
    7. ...
    8. }
    To copy to clipboard, switch view to plain text mode 

    Am I misunderstanding something?

  2. #2
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Disturbing: const QString &

    Are you sure?
    Can you post the entire function?

  3. #3
    Join Date
    Feb 2007
    Location
    Philadelphia, USA
    Posts
    255
    Thanks
    43
    Thanked 21 Times in 21 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Disturbing: const QString &

    Here's the function. It's part of a big program, and I can't isolate the problem easily. But the fact is that when I take out the "QString path=path_in;" line and replace "path_in" by "path" in the function arguments, I get a serious problem.

    I think this could be a bug with MinGW g++ ? !!!

    Qt Code:
    1. void update_node(const QString &path_in,bool do_emit_signal) {
    2. QString path=path_in; //apparently this is important :(
    3. if (!nodes.contains(path)) return;
    4. if (!nodes[path].needs_to_be_updated) return;
    5. nodes[path].needs_to_be_updated=false;
    6. nodes[path].children.clear();
    7. QList<HaiQTag> tags=core->tagManager->byPath(path);
    8. QStringList search_paths=include_search_paths;
    9. search_paths << QFileInfo(path).path();
    10. QStringList included_paths;
    11. for (int j=0; j<tags.count(); j++) {
    12. if (tags[j].tagtype=="pound_include") {
    13. QString holdstr=get_include_file_path(tags[j].signature,search_paths);;
    14. if (!holdstr.isEmpty())
    15. included_paths << holdstr;
    16. }
    17. }
    18. for (int j=0; j<included_paths.count(); j++) {
    19. QString path2=included_paths[j];
    20. if (!nodes.contains(path2)) {
    21. core->fileManager->addFile(path2);
    22. visible_files_node newnode;
    23. newnode.path=path2;
    24. newnode.needs_to_be_updated=true;
    25. nodes[path2]=newnode;
    26. }
    27. if (!nodes[path].children.contains(path2)) {
    28. nodes[path].children << path2;
    29. }
    30. if (nodes[path2].needs_to_be_updated)
    31. update_node(path2,false); //Here's the recursive part where the value of path becomes corrupted
    32. }
    33. if (do_emit_signal) emit updated();
    34. }
    To copy to clipboard, switch view to plain text mode 

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Disturbing: const QString &

    Quote Originally Posted by magland View Post
    update_node(path2,false); //Here's the recursive part where the value of path becomes corrupted
    But it's path2 not path.

    What happens if you change your code to:
    Qt Code:
    1. if (nodes[path2].needs_to_be_updated) {
    2. static int level = 0;
    3. qDebug() << "Before" << ++level << path << in_path;
    4. update_node(path2,false); //Here's the recursive part where the value of path becomes corrupted
    5. qDebug() << "After " << level-- << path << in_path;
    6. }
    To copy to clipboard, switch view to plain text mode 
    ?

  5. #5
    Join Date
    Feb 2007
    Location
    Philadelphia, USA
    Posts
    255
    Thanks
    43
    Thanked 21 Times in 21 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Disturbing: const QString &

    Thanks, Jacek. I put in those type of debug strings as you suggested (code is at the bottom)... and now I'm really starting to be worried of a fundamental bug in the compiler.

    The "path" variable changes right in the middle of the function, during a call to a completely different function. I should mention that the "update_node()" function is in a plugin library, and the implementation of the offending "addFile()" is in the main application.

    Here's the log that I get out, using the two scenarios. Notice that the "path" variable changes right between debug 5 and debug 6.

    Qt Code:
    1. LOG OUTPUT SCENARIO #1
    2. ...
    3. 0 update_node:::::1: "c:/qt/4.3.2/include/qtgui/qapplication"
    4. 0 update_node:::::2: "c:/qt/4.3.2/include/qtgui/qapplication"
    5. 0 update_node:::::3: "c:/qt/4.3.2/include/qtgui/qapplication"
    6. 0 update_node:::::4: "c:/qt/4.3.2/include/qtgui/qapplication"
    7. 0 update_node:::::5: "c:/qt/4.3.2/include/qtgui/qapplication"
    8. 0 update_node:::::6: "c:/qt/4.3.2/include/qtgui/qwidget"
    9. 0 update_node:::::7: "c:/qt/4.3.2/include/qtgui/qwidget"
    10. 0 update_node:::::8: "c:/qt/4.3.2/include/qtgui/qwidget"
    11. 0 update_node:::::9: "c:/qt/4.3.2/include/qtgui/qwidget"
    12. 1 update_node:::::1: "c:/qt/4.3.2/include/qtgui/qapplication.h"
    13. 1 update_node:::::2: "c:/qt/4.3.2/include/qtgui/qapplication.h"
    14. 1 update_node:::::3: "c:/qt/4.3.2/include/qtgui/qapplication.h"
    15. 1 update_node:::::11: "c:/qt/4.3.2/include/qtgui/qapplication.h"
    16. 0 update_node:::::10: "c:/qt/4.3.2/include/qtgui/qwidget"
    17. 0 update_node:::::11: "c:/qt/4.3.2/include/qtgui/qwidget"
    18. 0 update_node:::::1: "c:/qt/4.3.2/include/qtgui/qwidget"
    19. 0 update_node:::::2: "c:/qt/4.3.2/include/qtgui/qwidget"
    20. 0 update_node:::::3: "c:/qt/4.3.2/include/qtgui/qwidget"
    21. 0 update_node:::::4: "c:/qt/4.3.2/include/qtgui/qwidget"
    22. 0 update_node:::::5: "c:/qt/4.3.2/include/qtgui/qwidget"
    23. 0 update_node:::::6: "c:/qt/4.3.2/include/qtcore/qdebug"
    24. 0 update_node:::::7: "c:/qt/4.3.2/include/qtcore/qdebug"
    25. 0 update_node:::::8: "c:/qt/4.3.2/include/qtcore/qdebug"
    26. 0 update_node:::::9: "c:/qt/4.3.2/include/qtcore/qdebug"
    27. ...
    28.  
    29.  
    30. LOG OUTPUT SCENARIO #2
    31. ...
    32. 0 update_node:::::1: "c:/qt/4.3.2/include/qtgui/qapplication"
    33. 0 update_node:::::2: "c:/qt/4.3.2/include/qtgui/qapplication"
    34. 0 update_node:::::3: "c:/qt/4.3.2/include/qtgui/qapplication"
    35. 0 update_node:::::4: "c:/qt/4.3.2/include/qtgui/qapplication"
    36. 0 update_node:::::5: "c:/qt/4.3.2/include/qtgui/qapplication"
    37. 0 update_node:::::6: "c:/qt/4.3.2/include/qtgui/qapplication"
    38. 0 update_node:::::7: "c:/qt/4.3.2/include/qtgui/qapplication"
    39. 0 update_node:::::8: "c:/qt/4.3.2/include/qtgui/qapplication"
    40. 0 update_node:::::9: "c:/qt/4.3.2/include/qtgui/qapplication"
    41. 1 update_node:::::1: "c:/qt/4.3.2/include/qtgui/qapplication.h"
    42. 1 update_node:::::2: "c:/qt/4.3.2/include/qtgui/qapplication.h"
    43. 1 update_node:::::3: "c:/qt/4.3.2/include/qtgui/qapplication.h"
    44. 1 update_node:::::11: "c:/qt/4.3.2/include/qtgui/qapplication.h"
    45. 0 update_node:::::10: "c:/qt/4.3.2/include/qtgui/qapplication"
    46. 0 update_node:::::11: "c:/qt/4.3.2/include/qtgui/qapplication"
    47. 0 update_node:::::1: "c:/qt/4.3.2/include/qtgui/qwidget"
    48. 0 update_node:::::2: "c:/qt/4.3.2/include/qtgui/qwidget"
    49. 0 update_node:::::3: "c:/qt/4.3.2/include/qtgui/qwidget"
    50. 0 update_node:::::4: "c:/qt/4.3.2/include/qtgui/qwidget"
    51. 0 update_node:::::5: "c:/qt/4.3.2/include/qtgui/qwidget"
    52. 0 update_node:::::6: "c:/qt/4.3.2/include/qtgui/qwidget"
    53. 0 update_node:::::7: "c:/qt/4.3.2/include/qtgui/qwidget"
    54. 0 update_node:::::8: "c:/qt/4.3.2/include/qtgui/qwidget"
    55. 0 update_node:::::9: "c:/qt/4.3.2/include/qtgui/qwidget"
    56. ...
    To copy to clipboard, switch view to plain text mode 


    And here's the code that produced these two (only difference is in the top three lines):

    CODE FOR SCENARIO #1
    Qt Code:
    1. void update_node(const QString &path) {
    2. static int level=0;
    3. //QString path=path_in; //apparently this is important :(
    4. qDebug() << level << "update_node:::::1:" <<path;
    5. if (!nodes.contains(path)) return;
    6. if (!nodes[path].needs_to_be_updated) return;
    7. nodes[path].needs_to_be_updated=false;
    8. nodes[path].children.clear();
    9. QList<HaiQTag> tags=core->tagManager->byPath(path);
    10. emit file_tags_updated(path,tags);
    11. QStringList search_paths=include_search_paths;
    12. search_paths << QFileInfo(path).path();
    13. QStringList included_paths;
    14. qDebug() << level << "update_node:::::2:" <<path;
    15. for (int j=0; j<tags.count(); j++) {
    16. if (tags[j].tagtype=="pound_include") {
    17. QString holdstr=get_include_file_path(tags[j].signature,search_paths);;
    18. if (!holdstr.isEmpty())
    19. included_paths << holdstr;
    20. }
    21. }
    22. qDebug() << level << "update_node:::::3:" <<path;
    23. for (int j=0; j<included_paths.count(); j++) {
    24. QString path2=included_paths[j];
    25. qDebug() << level << "update_node:::::4:" <<path;
    26. if (!nodes.contains(path2)) {
    27. qDebug() << level << "update_node:::::5:" <<path;
    28. core->fileManager->addFile(path2);
    29. qDebug() << level << "update_node:::::6:" <<path;
    30. visible_files_node newnode;
    31. newnode.path=path2;
    32. newnode.needs_to_be_updated=true;
    33. nodes[path2]=newnode;
    34. }
    35. qDebug() << level << "update_node:::::7:" <<path;
    36. if ((!nodes[path].children.contains(path2))&&(path!=path2)) {
    37. nodes[path].children << path2;
    38. }
    39. qDebug() << level << "update_node:::::8:" <<path;
    40. if (nodes[path2].needs_to_be_updated) {
    41. qDebug() << level << "update_node:::::9:" <<path;
    42. level++;
    43. update_node(path2);
    44. level--;
    45. qDebug() << level << "update_node:::::10:" <<path;
    46. }
    47. }
    48. qDebug() << level << "update_node:::::11:" << path;
    49. }
    To copy to clipboard, switch view to plain text mode 


    CODE FOR SCENARIO #2
    Qt Code:
    1. void update_node(const QString &path_in) {
    2. static int level=0;
    3. QString path=path_in; //apparently this is important :(
    4. qDebug() << level << "update_node:::::1:" <<path;
    5. if (!nodes.contains(path)) return;
    6. if (!nodes[path].needs_to_be_updated) return;
    7. nodes[path].needs_to_be_updated=false;
    8. nodes[path].children.clear();
    9. QList<HaiQTag> tags=core->tagManager->byPath(path);
    10. emit file_tags_updated(path,tags);
    11. QStringList search_paths=include_search_paths;
    12. search_paths << QFileInfo(path).path();
    13. QStringList included_paths;
    14. qDebug() << level << "update_node:::::2:" <<path;
    15. for (int j=0; j<tags.count(); j++) {
    16. if (tags[j].tagtype=="pound_include") {
    17. QString holdstr=get_include_file_path(tags[j].signature,search_paths);;
    18. if (!holdstr.isEmpty())
    19. included_paths << holdstr;
    20. }
    21. }
    22. qDebug() << level << "update_node:::::3:" <<path;
    23. for (int j=0; j<included_paths.count(); j++) {
    24. QString path2=included_paths[j];
    25. qDebug() << level << "update_node:::::4:" <<path;
    26. if (!nodes.contains(path2)) {
    27. qDebug() << level << "update_node:::::5:" <<path;
    28. core->fileManager->addFile(path2);
    29. qDebug() << level << "update_node:::::6:" <<path;
    30. visible_files_node newnode;
    31. newnode.path=path2;
    32. newnode.needs_to_be_updated=true;
    33. nodes[path2]=newnode;
    34. }
    35. qDebug() << level << "update_node:::::7:" <<path;
    36. if ((!nodes[path].children.contains(path2))&&(path!=path2)) {
    37. nodes[path].children << path2;
    38. }
    39. qDebug() << level << "update_node:::::8:" <<path;
    40. if (nodes[path2].needs_to_be_updated) {
    41. qDebug() << level << "update_node:::::9:" <<path;
    42. level++;
    43. update_node(path2);
    44. level--;
    45. qDebug() << level << "update_node:::::10:" <<path;
    46. }
    47. }
    48. qDebug() << level << "update_node:::::11:" << path;
    49. }
    To copy to clipboard, switch view to plain text mode 


    and here is the declaration of addFile...

    Qt Code:
    1. void addFile(const QString &path);
    To copy to clipboard, switch view to plain text mode 

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Disturbing: const QString &

    Quote Originally Posted by magland View Post
    The "path" variable changes right in the middle of the function, during a call to a completely different function.
    This means that we have to take a look at this completely different function. It isn't time for worrying yet.

    Probably your code does something similar to this:
    Qt Code:
    1. #include <iostream>
    2.  
    3. int z = 0;
    4.  
    5. void bar( int y )
    6. {
    7. z = y;
    8. }
    9.  
    10. void foo( const int & x )
    11. {
    12. std::cerr << x << std::endl;
    13. bar( 1 );
    14. std::cerr << x << std::endl;
    15. }
    16.  
    17. int main()
    18. {
    19. foo( z );
    20. return 0;
    21. }
    To copy to clipboard, switch view to plain text mode 

  7. The following 2 users say thank you to jacek for this useful post:

    Gopala Krishna (20th November 2007), magland (17th November 2007)

  8. #7
    Join Date
    Feb 2007
    Location
    Philadelphia, USA
    Posts
    255
    Thanks
    43
    Thanked 21 Times in 21 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Disturbing: const QString &

    Ok, I see what you are saying. Now I see the danger of passing things by reference (even if declared const). The advantage is that the parameter does not need to be copied, but the tradeoff is that you need to worry about whether the variable is changed part way through the execution of the function - not within the function but elsewhere.

    This is probably what was happening to me. But I will never know, because I've restructured my program to avoid the recursion (I'm now using a queuing system to do the same task).

    Based on a recent recommendation on this forum I changed my coding habits and use "const QString &" everywhere instead of "QString".... but now I see that I need to be more careful. Do you have a recommendation of what precautions I need to take with this?

    Thanks!



    Quote Originally Posted by jacek View Post
    This means that we have to take a look at this completely different function. It isn't time for worrying yet.

    Probably your code does something similar to this:
    Qt Code:
    1. #include <iostream>
    2.  
    3. int z = 0;
    4.  
    5. void bar( int y )
    6. {
    7. z = y;
    8. }
    9.  
    10. void foo( const int & x )
    11. {
    12. std::cerr << x << std::endl;
    13. bar( 1 );
    14. std::cerr << x << std::endl;
    15. }
    16.  
    17. int main()
    18. {
    19. foo( z );
    20. return 0;
    21. }
    To copy to clipboard, switch view to plain text mode 

  9. The following user says thank you to magland for this useful post:

    Gopala Krishna (20th November 2007)

  10. #8
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: Disturbing: const QString &

    Quote Originally Posted by jacek View Post
    This means that we have to take a look at this completely different function. It isn't time for worrying yet.

    Probably your code does something similar to this:
    Qt Code:
    1. #include <iostream>
    2.  
    3. int z = 0;
    4.  
    5. void bar( int y )
    6. {
    7. z = y;
    8. }
    9.  
    10. void foo( const int & x )
    11. {
    12. std::cerr << x << std::endl;
    13. bar( 1 );
    14. std::cerr << x << std::endl;
    15. }
    16.  
    17. int main()
    18. {
    19. foo( z );
    20. return 0;
    21. }
    To copy to clipboard, switch view to plain text mode 
    Very cool observation jacek :-)

    So basically in the code posted by magland, it seems that the parameter passed is a class member variable(as there is an emit statement, the func should be a class member) which is modified somewhere may be in a slot.
    The actual answer to whether the reference form should be used or not is a dependent question. It depends on whether you modify the parameter sent outside the function when the function with const reference is not yet returned.

    Anyway, many thanks Jacek as well as magland for exposing such a kind of potential bug.
    A lesson learnt well in the right time
    The biggest difference between time and space is that you can't reuse time.
    -- Merrick Furst

  11. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Disturbing: const QString &

    Quote Originally Posted by magland View Post
    Based on a recent recommendation on this forum I changed my coding habits and use "const QString &" everywhere instead of "QString".... but now I see that I need to be more careful.
    It's recommended to pass objects by reference to avoid copying, but on the other hand in Qt it's cheap to copy implicitly shared classes.

    Quote Originally Posted by magland View Post
    Do you have a recommendation of what precautions I need to take with this?
    I was thinking about this for few days and I couldn't come up with any rules. You situation is a bit similar to:
    Qt Code:
    1. ...
    2. v.append( v[0] );
    To copy to clipboard, switch view to plain text mode 
    The argument is passed as reference, but it must be copied when QVector needs to reallocate data. You can easily identify such situation in a single data structure, but the problem arises when the data is passed between many classes. But I would simply classify that as one of those Bad Things(tm) that might happen when you use global variables (or you have cycles in call graph).

  12. #10
    Join Date
    Feb 2007
    Location
    Philadelphia, USA
    Posts
    255
    Thanks
    43
    Thanked 21 Times in 21 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Disturbing: const QString &

    Thanks Jacek. I agree with you.

    After finding a number of subtle problems caused by passing by reference (in addition to the one I reported) I have concluded that it is important to NEVER pass arguments by reference UNLESS you can guarantee that the function does not access global variables, or "have cycles in the call graph" that may end up modifying the input variable. It is just not worth the danger! There's nothing worse than problems that occur mysteriously once in every 1000 calls.

    Of course, passing by reference is good, if you can ensure such things. I don't use global variables, but I do use a model/view framework which inevitably will have some cycles or recursive calls. Therefore, I need to be careful about it.

Similar Threads

  1. qt 4.2.2 install in tru64 cxx
    By try to remember in forum Installation and Deployment
    Replies: 0
    Last Post: 30th March 2007, 07:43
  2. Convert from iso-8859-1 to... Something else :-)
    By Nyphel in forum Qt Programming
    Replies: 4
    Last Post: 7th March 2007, 17:59
  3. QTableView paints too much
    By Jimmy2775 in forum Qt Programming
    Replies: 2
    Last Post: 26th July 2006, 18:42
  4. Delegates and Table
    By ankurjain in forum Qt Programming
    Replies: 8
    Last Post: 18th May 2006, 19:47
  5. Replies: 4
    Last Post: 24th March 2006, 22:50

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.