Thread: Is this a valid way to do a copy instead of a memcpy?

  1. #1
    Registered User
    Join Date
    Oct 2017
    Posts
    23

    Is this a valid way to do a copy instead of a memcpy?

    Basically the lines in question below are


    queue[tail] = element;
    vs.
    memcpy(&queue[tail], &element, sizeof(T));


    Is doing the first (queue[tail] = element) a valid way to do this? I have included a simple stupid example.


    Code:
    template <typename T>
    class Stupid
    {
    protected:
            T *queue;
            uint16_t head;
            uint16_t tail;
            size_t numElements;
    public:
            Stupid(size_t numElements, size_t alignment) :
              head(0), tail(0), numElements(numElements)
                    {
                            size_t size = sizeof(T)*numElements;
                            posix_memalign((void**)(&queue), alignment, size);
                    }
            virtual int
            enQueue(T &element)
                    {
                            //void *temp = &element;
                            queue[tail] = element;
                            //memcpy(&queue[tail], temp, sizeof(T));
                            tail++;
                            if (tail >= numElements)
                                    tail = 0;
                    }
    };

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    You should definitely NOT use memcpy.
    If the type of T contains pointers to data then memcpy won't copy that data.
    For example, consider std::string.
    If you naively memcpy it you'll end up with two strings pointing to the exact same data.
    If you make a change to one, you will also change the other. And if the change causes it to be reallocated to a different position in memory then the situation is even worse since now one of the strings will point to deallocated memory.
    But since std::string (and any properly programmed type with allocated data) will have overloaded operator=, using = will work just fine, copying both the basic structure data and also creating new allocated memory for the pointers to point to.
    Code:
    #include <iostream>
    #include <string>
    #include <cstring>
     
    template <typename T>
    class Queue {
    protected:
        T *data;
        size_t head;
        size_t tail;
        size_t maxSize;
    public:
        Queue(size_t maxSize) :
          data(new T[maxSize]), head(0), tail(0), maxSize(maxSize) {
        }
        void push(const T &elem) {
            // First try it with memcpy and then try it with =
            //data[tail] = elem;
            std::memcpy(&data[tail], (void*)&elem, sizeof elem);
            tail = (tail + 1) % maxSize;
        }
        T pop() {
            T elem = data[head];
            head = (head + 1) % maxSize;
            return elem;
        }
    };
     
    int main() {
        std::string s{"hello world"};
        Queue<std::string> q(10);
        q.push(s);
        s[6] = 'X';   // If you use memcpy then this change will also change the string data returned from the queue.
        std::string s2 = q.pop();
        std::cout << s2 << '\n';
    }
    Last edited by john.c; 08-25-2018 at 09:41 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Oct 2017
    Posts
    23
    >But since std::string (and any properly programmed type with allocated data) will have overloaded operator=, using = will work just fine, copying both the basic structure data and also creating new allocated memory for the pointers to point to.

    So, this is a user runtime that interacts with hardware. The type passed into the "enQueue" is shared with the firmware and those structs are defined as C code, as the firmware is written in C (the user mode driver that sits on top is C++, just like OpenMP and OpenCL).

    Not everything will have an overloaded = operator. Strings ultimately won't be passed in through here, but really a set of 64 byte descriptors (none of the fields will have a char*; everything will be explicitly sized).

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I think what's important here is that there is no way the commented memcpy() will do something that assignment won't.
    Not everything will have an overloaded = operator.
    If the type can't be assigned, that will be a problem, but it's one that I don't think you'll run into. The reason is lots of types are assignable, even C structs of plain old data can be assigned.

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    You left a lot of info out of the original problem description! So what you're saying is that you're sure that memcpy will work just fine and your question is whether = will also work. As far as copying one struct to another, = should work just fine if memcpy works.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  6. #6
    Registered User
    Join Date
    Oct 2017
    Posts
    23
    Quote Originally Posted by john.c View Post
    You left a lot of info out of the original problem description! So what you're saying is that you're sure that memcpy will work just fine and your question is whether = will also work. As far as copying one struct to another, = should work just fine if memcpy works.
    Right. What you've said is probably a better way to describe the question. Using memcpy didn't seem very C++-ish to me, so that's why I asked.

    Thanks.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 11-20-2013, 01:34 PM
  2. Replies: 2
    Last Post: 10-13-2013, 07:36 PM
  3. Socket file descriptor valid and then not valid
    By Florian in forum C Programming
    Replies: 3
    Last Post: 05-22-2010, 08:23 AM
  4. Replies: 2
    Last Post: 03-11-2009, 07:52 AM
  5. Trying to copy buffers using memcpy in C under UNIX
    By Meeper in forum C Programming
    Replies: 3
    Last Post: 07-26-2003, 08:51 AM

Tags for this Thread