Results 1 to 7 of 7

Thread: Doubt about deep copy using QByteArray::append() and QByteArray::fromRawData()

  1. #1
    Join Date
    Jun 2011
    Location
    Porto Alegre, Brazil
    Posts
    482
    Thanks
    165
    Thanked 2 Times in 2 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Doubt about deep copy using QByteArray::append() and QByteArray::fromRawData()

    Hello!

    Simple question: are the next two codes equal?

    1:
    Qt Code:
    1. QByteArray bytesReceived;
    2. char bytesReceivedTemp[SOCKET_BUFFER_SIZE];
    3.  
    4. //fill bytesReceivedTemp
    5.  
    6. bytesReceived.append(QByteArray::fromRawData(bytesReceivedTemp,SOCKET_BUFFER_SIZE));
    To copy to clipboard, switch view to plain text mode 

    2:
    Qt Code:
    1. QByteArray bytesReceived;
    2. char bytesReceivedTemp[SOCKET_BUFFER_SIZE];
    3.  
    4. //fill bytesReceivedTemp
    5.  
    6. bytesReceived.append(bytesReceivedTemp,SOCKET_BUFFER_SIZE);
    To copy to clipboard, switch view to plain text mode 

    This question is related to that problem of doing a deep copy or having two objects sharing the same data. The QByteArray::fromRawData() states that it performs a "shallow copy" of bytesReceivedTemp's data to the returned QByteArray, needing the first one to be valid while using the second and only for reading (if a modification is attempted, Qt will make a deep copy of the data). Qt Assistant also says that when append() is used against a empty QByteArray (the above situation, different from QByteArray bytesReceived = "";), it also performs a "shallow copy" of the appended data instead of a deep one. It would seem, therefore, that the first code is quite redundant if it is performed only once, since it's performing a "shallow copy" of another "shallow copy", while the second is not (in a second iteration with a persistent (e.g. static) bytesReceived which isn't empty anymore would make the first code perform only one "shallow copy" while the second would make a deep one).

    Am I correct in all what I sad? Which would be the smartest way of handling this in a embedded development situation, when "shallow copies" are preferred over deep ones, and if bytesReceived is handled as mentioned in the last parenthesis?


    Thanks,

    Momergil
    May the Lord be with you. Always.

  2. #2
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Doubt about deep copy using QByteArray::append() and QByteArray::fromRawData()

    No the two are not equal. If bytesReceived is empty then the first option merely points at the existing buffer and the second immediately makes a copy of the buffer into its own storage. If bytesReceived is not empty at the time of the append() call then both copy the data out of the existing buffer into their own storage.

    Which would be the smartest way of handling this in a embedded development situation,
    That depends entirely on what you intend to do with the bytesReceived QByteArray. You don't tell us, but in your code it is non-const and therefore we assume it will be modified. In that case there will be a deep copy of the original data anyway.

  3. The following user says thank you to ChrisW67 for this useful post:

    Momergil (9th May 2014)

  4. #3
    Join Date
    Jun 2011
    Location
    Porto Alegre, Brazil
    Posts
    482
    Thanks
    165
    Thanked 2 Times in 2 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Doubt about deep copy using QByteArray::append() and QByteArray::fromRawData()

    Thanks Chris for the reply.

    Quote Originally Posted by ChrisW67 View Post
    ... and the second immediately makes a copy of the buffer into its own storage.
    Really? Well, that certainly was not what I understood from Qt Assistant, which seems to hold that the second would also merely points at the existing buffer if bytesReceived is empty:

    Note: QByteArray is an implicitly shared class. Consequently, if this is an empty QByteArray, then this will just share the data held in ba. In this case, no copying of data is done, taking constant time. If a shared instance is modified, it will be copied (copy-on-write), taking linear time.

    If this is not an empty QByteArray, a deep copy of the data is performed, taking linear time.
    I guess Qt Assistant is not much clear in this case... (Note: using Qt 4.8)

    Quote Originally Posted by ChrisW67 View Post
    If bytesReceived is not empty at the time of the append() call then both copy the data
    In other words, if bytesReceived is not empty, than calling QByteArray::fromRawData() is useless? o.O Is there a way to "correct" this situation?

    Quote Originally Posted by ChrisW67 View Post
    in your code it is non-const and therefore we assume it will be modified.
    Actually it's non-constant to avoid instantiating a new QByteArray each time new data arrives, but the bytesReceived is not supposed to be modified with the exception to a call of QByteArray::clear(), which AFAIK wouldn't make a call to the copy-on-write since it's not editing the data inside the QByteArray, but only the QByteArray itself (please correct me if I'm wrong!).
    May the Lord be with you. Always.

  5. #4
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Doubt about deep copy using QByteArray::append() and QByteArray::fromRawData()

    OK, I misread your original options as:
    Qt Code:
    1. QByteArray bytesReceived;
    2. char bytesReceivedTemp[SOCKET_BUFFER_SIZE];
    3.  
    4. bytesReceived.append(QByteArray::fromRawData(bytesReceivedTemp,SOCKET_BUFFER_SIZE)); // 1
    5. bytesReceived.append(QByteArray(bytesReceivedTemp,SOCKET_BUFFER_SIZE)); // 2
    To copy to clipboard, switch view to plain text mode 
    In this case your two options use two different methods of constructing the QByteArray that you append to the array you declared. These two methods differ: option 2 copies immediately the other does not. By the time append() runs on the empty target array the copy has already been made.

    Your second option was actually:
    Qt Code:
    1. bytesReceived.append(bytesReceivedTemp,SOCKET_BUFFER_SIZE); // 2
    To copy to clipboard, switch view to plain text mode 
    This version of append() never constructs a QByteArray to append, so you never get the implicit sharing of QByteArray buffers. It simply reallocates the internal buffer of the target QByteArray, reallocating space if required, and copies the specified bytes onto the end of the buffer.


    You cannot "correct" the situation. If the target array already contains data then append() must copy the content of its argument onto the end of its buffer (allocating or reallocating memory as required). There is no magical way to make two independent buffers contiguous in memory to "append" without copying.
    Last edited by ChrisW67; 10th May 2014 at 22:52.

  6. The following user says thank you to ChrisW67 for this useful post:

    Momergil (12th May 2014)

  7. #5
    Join Date
    Jun 2011
    Location
    Porto Alegre, Brazil
    Posts
    482
    Thanks
    165
    Thanked 2 Times in 2 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Doubt about deep copy using QByteArray::append() and QByteArray::fromRawData()

    Hello Chris and thanks again for the reply!

    So let me see if I understood your now corrected explanation with a example (particularly the situation I want now to apply all this).

    I have a socket connection from which data arrives into a char[]-buffer. I want to construct a temporary QByteArray that will never be modified (constant), only to manipulate these data as a QByteArray instead of a char[]. For this, I want to do a shallow copy, so I may use both options

    Qt Code:
    1. char bytesReceivedTemp[SOCKET_BUFFER_SIZE];
    2.  
    3. const QByteArray bytesReceived = QByteArray::fromRawData(bytesReceivedTemp,SOCKET_BUFFER_SIZE)); //Option 1
    4.  
    5. const QByteArray bytesReceived(bytesReceivedTemp,SOCKET_BUFFER_SIZE); //Option 2
    To copy to clipboard, switch view to plain text mode 

    , for both o them use QByteArray's implicit sharing of data. For this, I simply can't use append(), for in doing it I'll necessarily make a deep copy (what still seems to go against Qt Assistant's append() instructions, but that's what I understood of your explanations

    (...)option 2 copies immediately(...)
    (...)copies immediately the other does not(...) //which means, it copies later with append()
    (...) and copies the specified bytes onto the end of the buffer. // For bytesReceived.append(bytesReceivedTemp,SOCKET_BUFF ER_SIZE)
    ). But what may happen is that the data package received in the socket system may come in fractions, so I'll need to store the already received data in a different QByteArray (now a deep copy) and wait for the new data pack from the socket. When it arrives, I should create a new QByteArray with a shallow copy to the first part of the pack plus a shallow copy of the new data recently received. The resulting template code:

    Qt Code:
    1. QByteArray previousData;
    2. char bytesReceivedTemp[SOCKET_BUFFER_SIZE];
    3. memset(&bytesReceivedTemp,'\0',SOCKET_BUFFER_SIZE);
    4.  
    5. while(true)
    6. {
    7. socket_read(bytesReceivedTemp). //simplified
    8.  
    9. const QByteArray bytesReceived(previousData + QByteArray::fromRawData(bytesReceivedTemp,SOCKET_BUFFER_SIZE)); //bytesReceived with two shallow copies
    10.  
    11. switch(bytesReceived.at(0))
    12. {
    13. case PACK_HEADER_1: //identifies the pack
    14. {
    15. if (bytesReceived.size() < PACK_HEADER_1_SIZE) //verify if pack is fragmented
    16. {
    17. previousData = bytesReceived.mid(0,bytesReceived.size()); //Performs a deep copy of the current fraction of the pack
    18. continue;
    19. }
    20.  
    21. //Process...
    22. }
    23.  
    24. //...
    25. }
    26. }
    To copy to clipboard, switch view to plain text mode 

    Note: obviously the algorithm is simplified.


    Thanks,

    Momergil
    May the Lord be with you. Always.

  8. #6
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Doubt about deep copy using QByteArray::append() and QByteArray::fromRawData()

    Quote Originally Posted by Momergil View Post
    Hello Chris and thanks again for the reply!

    So let me see if I understood your now corrected explanation with a example (particularly the situation I want now to apply all this).

    I have a socket connection from which data arrives into a char[]-buffer. I want to construct a temporary QByteArray that will never be modified (constant), only to manipulate these data as a QByteArray instead of a char[]. For this, I want to do a shallow copy, so I may use both options

    Qt Code:
    1. char bytesReceivedTemp[SOCKET_BUFFER_SIZE];
    2.  
    3. const QByteArray bytesReceived = QByteArray::fromRawData(bytesReceivedTemp,SOCKET_BUFFER_SIZE)); //Option 1
    4.  
    5. const QByteArray bytesReceived(bytesReceivedTemp,SOCKET_BUFFER_SIZE); //Option 2
    To copy to clipboard, switch view to plain text mode 
    No, the constructor you are using in Option 2 makes a deep copy outright. You want option 1.

    But what may happen is that the data package received in the socket system may come in fractions, so I'll need to store the already received data in a different QByteArray (now a deep copy) and wait for the new data pack from the socket. When it arrives, I should create a new QByteArray with a shallow copy to the first part of the pack plus a shallow copy of the new data recently received. The resulting template code:

    Qt Code:
    1. QByteArray previousData;
    2. char bytesReceivedTemp[SOCKET_BUFFER_SIZE];
    3. memset(&bytesReceivedTemp,'\0',SOCKET_BUFFER_SIZE);
    4.  
    5. while(true)
    6. {
    7. socket_read(bytesReceivedTemp). //simplified
    8.  
    9. const QByteArray bytesReceived(previousData + QByteArray::fromRawData(bytesReceivedTemp,SOCKET_BUFFER_SIZE)); //bytesReceived with two shallow copies
    To copy to clipboard, switch view to plain text mode 
    You are constructing a QByteArray bytesReceived that shares its internals structure (implicit sharing) with a temporary QByteArray (that is promptly destroyed). The temporary byte array is the one returned by QByteArray::operator+() after it creates an internal buffer containing the content of previousData and bytesReceivedTemp. You have not avoided a deep copy (and cannot). You might as well just:
    Qt Code:
    1. previousData.append(QByteArray::fromRawData(bytesReceivedTemp,SOCKET_BUFFER_SIZE));
    To copy to clipboard, switch view to plain text mode 

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

    Momergil (14th May 2014)

  10. #7
    Join Date
    Jun 2011
    Location
    Porto Alegre, Brazil
    Posts
    482
    Thanks
    165
    Thanked 2 Times in 2 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Doubt about deep copy using QByteArray::append() and QByteArray::fromRawData()

    Quote Originally Posted by ChrisW67 View Post
    You have not avoided a deep copy (and cannot).
    Really? Is there no other way of creating const QByteArray bytesReceived pointing to previousData and QByteArray::fromRawData(...) that avoids deep copy?

    Well, than all this effort was for almost nothing \o/ (almost because, the way it was, it seems I had some memory problems that seems to have been solved with this conversation).


    Well, life is hard :P

    Thanks, then, Chris for all.


    Momergil
    May the Lord be with you. Always.

Similar Threads

  1. Append/Prepend QString to QByteArray
    By ermustaqbal in forum Newbie
    Replies: 5
    Last Post: 2nd August 2011, 07:19
  2. Replies: 1
    Last Post: 22nd June 2011, 08:12
  3. Replies: 3
    Last Post: 29th April 2010, 19:11
  4. [ SOLVED (kinda) ]copy structure to QByteArray
    By pdoria in forum Qt Programming
    Replies: 14
    Last Post: 17th October 2009, 14:42
  5. Replies: 9
    Last Post: 25th July 2009, 13:27

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.