Simple raw buffer queue implementationQueue Implementation(nearly) lock-free job queue of dynamic size...

My boss asked me to take a one-day class, then signs it up as a day off

How do ultrasonic sensors differentiate between transmitted and received signals?

Is there any significance to the Valyrian Stone vault door of Qarth?

How to prevent YouTube from showing already watched videos?

Is there a problem with hiding "forgot password" until it's needed?

Should my PhD thesis be submitted under my legal name?

Is a naturally all "male" species possible?

The most efficient algorithm to find all possible integer pairs which sum to a given integer

Organic chemistry Iodoform Reaction

Is it okay / does it make sense for another player to join a running game of Munchkin?

Installing PowerShell on 32-bit Kali OS fails

Blender - show edges angles “direction”

Simulating a probability of 1 of 2^N with less than N random bits

Hostile work environment after whistle-blowing on coworker and our boss. What do I do?

Invariance of results when scaling explanatory variables in logistic regression, is there a proof?

Did US corporations pay demonstrators in the German demonstrations against article 13?

What is the opposite of 'gravitas'?

How to check participants in at events?

Visiting the UK as unmarried couple

What will be the benefits of Brexit?

Pronouncing Homer as in modern Greek

Can a controlled ghast be a leader of a pack of ghouls?

Identify a stage play about a VR experience in which participants are encouraged to simulate performing horrific activities

Calculating the number of days between 2 dates in Excel



Simple raw buffer queue implementation


Queue Implementation(nearly) lock-free job queue of dynamic size (multiple read/write)STL queue implementationTemplated queue implementationBoost::pool based STL vector allocatorC++ Queue ImplementationSimple Queue ImplementationQueue With Variable Size BufferQueue Implementation in C++Implementation of a queue













2












$begingroup$


I am trying to implement a simple raw queue in C++. This is what I have come up with



#include <queue>
#include <cstdint>
#include <array>
#include <cstring>

class simple_queue
{
private:
static constexpr uint32_t max_msg_size = 4096;
using char_msg = std::array<char, max_msg_size>;
std::queue<char_msg> char_queue;

public:
simple_queue() = default;
~simple_queue() = default;
simple_queue(simple_queue&&) = default;
simple_queue& operator=(simple_queue&&) = default;

uint32_t write(const char* const buff, const uint32_t size) noexcept
{
const uint32_t size_to_copy = std::min(max_msg_size, size);
char_msg tmp_msg;
std::memcpy(&tmp_msg, buff, size_to_copy);
char_queue.push(std::move(tmp_msg));
return size_to_copy;
}

uint32_t read(char* const buff, const uint32_t size) noexcept
{
if (char_queue.empty())
{
return 0;
}
const uint32_t size_to_copy = std::min(max_msg_size, size);
std::memcpy(buff, &char_queue.front(), size_to_copy);
char_queue.pop();
return size_to_copy;
}
};


Note that I am trying to implement this queue just to store raw char buffers. As far as I understand making it a template does not make sense in this case.



I have played with it a bit and it seems to work as I expect.




  • What can I change with this implementation?

  • Does it make sense to use a custom allocator in here? I am allocating memory every time I write to the queue; how can I use a custom allocator to allocate some default chunk of memory when the queue is constructed?










share|improve this question









$endgroup$

















    2












    $begingroup$


    I am trying to implement a simple raw queue in C++. This is what I have come up with



    #include <queue>
    #include <cstdint>
    #include <array>
    #include <cstring>

    class simple_queue
    {
    private:
    static constexpr uint32_t max_msg_size = 4096;
    using char_msg = std::array<char, max_msg_size>;
    std::queue<char_msg> char_queue;

    public:
    simple_queue() = default;
    ~simple_queue() = default;
    simple_queue(simple_queue&&) = default;
    simple_queue& operator=(simple_queue&&) = default;

    uint32_t write(const char* const buff, const uint32_t size) noexcept
    {
    const uint32_t size_to_copy = std::min(max_msg_size, size);
    char_msg tmp_msg;
    std::memcpy(&tmp_msg, buff, size_to_copy);
    char_queue.push(std::move(tmp_msg));
    return size_to_copy;
    }

    uint32_t read(char* const buff, const uint32_t size) noexcept
    {
    if (char_queue.empty())
    {
    return 0;
    }
    const uint32_t size_to_copy = std::min(max_msg_size, size);
    std::memcpy(buff, &char_queue.front(), size_to_copy);
    char_queue.pop();
    return size_to_copy;
    }
    };


    Note that I am trying to implement this queue just to store raw char buffers. As far as I understand making it a template does not make sense in this case.



    I have played with it a bit and it seems to work as I expect.




    • What can I change with this implementation?

    • Does it make sense to use a custom allocator in here? I am allocating memory every time I write to the queue; how can I use a custom allocator to allocate some default chunk of memory when the queue is constructed?










    share|improve this question









    $endgroup$















      2












      2








      2





      $begingroup$


      I am trying to implement a simple raw queue in C++. This is what I have come up with



      #include <queue>
      #include <cstdint>
      #include <array>
      #include <cstring>

      class simple_queue
      {
      private:
      static constexpr uint32_t max_msg_size = 4096;
      using char_msg = std::array<char, max_msg_size>;
      std::queue<char_msg> char_queue;

      public:
      simple_queue() = default;
      ~simple_queue() = default;
      simple_queue(simple_queue&&) = default;
      simple_queue& operator=(simple_queue&&) = default;

      uint32_t write(const char* const buff, const uint32_t size) noexcept
      {
      const uint32_t size_to_copy = std::min(max_msg_size, size);
      char_msg tmp_msg;
      std::memcpy(&tmp_msg, buff, size_to_copy);
      char_queue.push(std::move(tmp_msg));
      return size_to_copy;
      }

      uint32_t read(char* const buff, const uint32_t size) noexcept
      {
      if (char_queue.empty())
      {
      return 0;
      }
      const uint32_t size_to_copy = std::min(max_msg_size, size);
      std::memcpy(buff, &char_queue.front(), size_to_copy);
      char_queue.pop();
      return size_to_copy;
      }
      };


      Note that I am trying to implement this queue just to store raw char buffers. As far as I understand making it a template does not make sense in this case.



      I have played with it a bit and it seems to work as I expect.




      • What can I change with this implementation?

      • Does it make sense to use a custom allocator in here? I am allocating memory every time I write to the queue; how can I use a custom allocator to allocate some default chunk of memory when the queue is constructed?










      share|improve this question









      $endgroup$




      I am trying to implement a simple raw queue in C++. This is what I have come up with



      #include <queue>
      #include <cstdint>
      #include <array>
      #include <cstring>

      class simple_queue
      {
      private:
      static constexpr uint32_t max_msg_size = 4096;
      using char_msg = std::array<char, max_msg_size>;
      std::queue<char_msg> char_queue;

      public:
      simple_queue() = default;
      ~simple_queue() = default;
      simple_queue(simple_queue&&) = default;
      simple_queue& operator=(simple_queue&&) = default;

      uint32_t write(const char* const buff, const uint32_t size) noexcept
      {
      const uint32_t size_to_copy = std::min(max_msg_size, size);
      char_msg tmp_msg;
      std::memcpy(&tmp_msg, buff, size_to_copy);
      char_queue.push(std::move(tmp_msg));
      return size_to_copy;
      }

      uint32_t read(char* const buff, const uint32_t size) noexcept
      {
      if (char_queue.empty())
      {
      return 0;
      }
      const uint32_t size_to_copy = std::min(max_msg_size, size);
      std::memcpy(buff, &char_queue.front(), size_to_copy);
      char_queue.pop();
      return size_to_copy;
      }
      };


      Note that I am trying to implement this queue just to store raw char buffers. As far as I understand making it a template does not make sense in this case.



      I have played with it a bit and it seems to work as I expect.




      • What can I change with this implementation?

      • Does it make sense to use a custom allocator in here? I am allocating memory every time I write to the queue; how can I use a custom allocator to allocate some default chunk of memory when the queue is constructed?







      c++ performance queue






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked yesterday









      AliAli

      20129




      20129






















          1 Answer
          1






          active

          oldest

          votes


















          2












          $begingroup$

          You are not allocating per se when when writing to the queue. std::array is backed by a plain C-array on the stack, that gets moved.



          So you only ever allocate depending on the underlying container the std::queue is based on. By default this is a std::deque.



          I do not really understand the need for the std::array in the type though. Why not just use a std::string and limit the size of it to 4096? There is even a constructor that does explicitely that string (const char* s, size_t n)



          Before I get to the Code there are some other things I would like to mention:




          1. why are you not useing std::copy instead of memcpy. The former works better with C++ and will in the end almost always end up as memcpy?


          2. You do not need to define the special member functions. In fact you have forgotten 2 of then, aka copy assignment and copy constructor. Why do I say forgotten? Because there is no way to tell. So If you want your queue to be move only then you should actually delete those special member functions you dont want.


          3. In your read function you never check whether the size you want to read is actually valid. Is that intendend? If so why? A std::array is not initialized so the memory in it that is not written by you will be random. You are not writing to it but you are copying it around. So you should actually take the minimum out of size and queue.front().size()


          4. std::string has a member function std::string::copy that copyies a certain amount of chars to a buffer (http://www.cplusplus.com/reference/string/string/copy/). I would suggest to use that for writing back to the buffer



          That leads me to the following:



          #include <string>
          #include <queue>
          #include <vector>

          class simple_queue
          {
          private:
          static constexpr uint32_t max_msg_size = 4096;
          std::queue<std::string, std::vector<std::string>> char_queue;

          public:
          simple_queue(const simple_queue&) = delete;
          simple_queue& operator=(const simple_queue&) = delete;

          uint32_t write(const char* const buff, const uint32_t size) noexcept
          {
          const uint32_t size_to_copy = std::min(max_msg_size, size);
          char_queue.emplace(buff, size_to_copy);
          return size_to_copy;
          }

          uint32_t read(char* const buff, const uint32_t size) noexcept
          {
          if (char_queue.empty())
          {
          return 0;
          }
          std::string& msg = char_queue.front();
          const uint32_t size_to_copy = std::min(msg, size);
          msg.copy(buff, size_to_copy, 0);

          char_queue.pop();
          return size_to_copy;
          }
          };


          EDIT:



          I forgot to mention, that now you should use a std::vector as backing of the queue as your are not storing a gargantuan array but rather a mall std::string.



          Note that it actually ends up being the same. The std::deque based std::array implementation is backed by a linked list, so each array ends up in a node of a linked list, which is kind of similar to the separate allocation of the std::string






          share|improve this answer











          $endgroup$









          • 2




            $begingroup$
            You should not use "EDIT tags"; they are only confusing and distracting for people who come to the question or answer for the first time. Edits happen all the time, and anyone interested can just click to see the whole post history.
            $endgroup$
            – Juho
            yesterday










          • $begingroup$
            Thanks, all of your points are valid. I have updated the implementation and after running benchmarks it is performing much better. However there is still something I would like to improve. With every .emplace(buff, size_to_copy) the allocator for std::string is called, I would like to get rid of allocation and have it use a pre allocated chunk of memory. I was under the impression it might be easier to do so with std::array and that's why I opted to use that instead of std::string.
            $endgroup$
            – Ali
            yesterday












          • $begingroup$
            @miscco BTW, I did not get why you've mentioned to use std::vector, you mean I should use a vector of chars?
            $endgroup$
            – Ali
            yesterday








          • 1




            $begingroup$
            @Ali std::queue is a container-adaptor. The second template argument it takes is the underlying container. Consequently, in the example i replaced the default container std::deque with std::vector
            $endgroup$
            – miscco
            yesterday










          • $begingroup$
            @Ali Regarding your first comment, you will most likely never get rid of all allocations, as the std array is allocated into a container node anyway. In fact it even better to allocate a potentially smaller string than always putting a gargantuan array into std::deque node
            $endgroup$
            – miscco
            yesterday











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216097%2fsimple-raw-buffer-queue-implementation%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          2












          $begingroup$

          You are not allocating per se when when writing to the queue. std::array is backed by a plain C-array on the stack, that gets moved.



          So you only ever allocate depending on the underlying container the std::queue is based on. By default this is a std::deque.



          I do not really understand the need for the std::array in the type though. Why not just use a std::string and limit the size of it to 4096? There is even a constructor that does explicitely that string (const char* s, size_t n)



          Before I get to the Code there are some other things I would like to mention:




          1. why are you not useing std::copy instead of memcpy. The former works better with C++ and will in the end almost always end up as memcpy?


          2. You do not need to define the special member functions. In fact you have forgotten 2 of then, aka copy assignment and copy constructor. Why do I say forgotten? Because there is no way to tell. So If you want your queue to be move only then you should actually delete those special member functions you dont want.


          3. In your read function you never check whether the size you want to read is actually valid. Is that intendend? If so why? A std::array is not initialized so the memory in it that is not written by you will be random. You are not writing to it but you are copying it around. So you should actually take the minimum out of size and queue.front().size()


          4. std::string has a member function std::string::copy that copyies a certain amount of chars to a buffer (http://www.cplusplus.com/reference/string/string/copy/). I would suggest to use that for writing back to the buffer



          That leads me to the following:



          #include <string>
          #include <queue>
          #include <vector>

          class simple_queue
          {
          private:
          static constexpr uint32_t max_msg_size = 4096;
          std::queue<std::string, std::vector<std::string>> char_queue;

          public:
          simple_queue(const simple_queue&) = delete;
          simple_queue& operator=(const simple_queue&) = delete;

          uint32_t write(const char* const buff, const uint32_t size) noexcept
          {
          const uint32_t size_to_copy = std::min(max_msg_size, size);
          char_queue.emplace(buff, size_to_copy);
          return size_to_copy;
          }

          uint32_t read(char* const buff, const uint32_t size) noexcept
          {
          if (char_queue.empty())
          {
          return 0;
          }
          std::string& msg = char_queue.front();
          const uint32_t size_to_copy = std::min(msg, size);
          msg.copy(buff, size_to_copy, 0);

          char_queue.pop();
          return size_to_copy;
          }
          };


          EDIT:



          I forgot to mention, that now you should use a std::vector as backing of the queue as your are not storing a gargantuan array but rather a mall std::string.



          Note that it actually ends up being the same. The std::deque based std::array implementation is backed by a linked list, so each array ends up in a node of a linked list, which is kind of similar to the separate allocation of the std::string






          share|improve this answer











          $endgroup$









          • 2




            $begingroup$
            You should not use "EDIT tags"; they are only confusing and distracting for people who come to the question or answer for the first time. Edits happen all the time, and anyone interested can just click to see the whole post history.
            $endgroup$
            – Juho
            yesterday










          • $begingroup$
            Thanks, all of your points are valid. I have updated the implementation and after running benchmarks it is performing much better. However there is still something I would like to improve. With every .emplace(buff, size_to_copy) the allocator for std::string is called, I would like to get rid of allocation and have it use a pre allocated chunk of memory. I was under the impression it might be easier to do so with std::array and that's why I opted to use that instead of std::string.
            $endgroup$
            – Ali
            yesterday












          • $begingroup$
            @miscco BTW, I did not get why you've mentioned to use std::vector, you mean I should use a vector of chars?
            $endgroup$
            – Ali
            yesterday








          • 1




            $begingroup$
            @Ali std::queue is a container-adaptor. The second template argument it takes is the underlying container. Consequently, in the example i replaced the default container std::deque with std::vector
            $endgroup$
            – miscco
            yesterday










          • $begingroup$
            @Ali Regarding your first comment, you will most likely never get rid of all allocations, as the std array is allocated into a container node anyway. In fact it even better to allocate a potentially smaller string than always putting a gargantuan array into std::deque node
            $endgroup$
            – miscco
            yesterday
















          2












          $begingroup$

          You are not allocating per se when when writing to the queue. std::array is backed by a plain C-array on the stack, that gets moved.



          So you only ever allocate depending on the underlying container the std::queue is based on. By default this is a std::deque.



          I do not really understand the need for the std::array in the type though. Why not just use a std::string and limit the size of it to 4096? There is even a constructor that does explicitely that string (const char* s, size_t n)



          Before I get to the Code there are some other things I would like to mention:




          1. why are you not useing std::copy instead of memcpy. The former works better with C++ and will in the end almost always end up as memcpy?


          2. You do not need to define the special member functions. In fact you have forgotten 2 of then, aka copy assignment and copy constructor. Why do I say forgotten? Because there is no way to tell. So If you want your queue to be move only then you should actually delete those special member functions you dont want.


          3. In your read function you never check whether the size you want to read is actually valid. Is that intendend? If so why? A std::array is not initialized so the memory in it that is not written by you will be random. You are not writing to it but you are copying it around. So you should actually take the minimum out of size and queue.front().size()


          4. std::string has a member function std::string::copy that copyies a certain amount of chars to a buffer (http://www.cplusplus.com/reference/string/string/copy/). I would suggest to use that for writing back to the buffer



          That leads me to the following:



          #include <string>
          #include <queue>
          #include <vector>

          class simple_queue
          {
          private:
          static constexpr uint32_t max_msg_size = 4096;
          std::queue<std::string, std::vector<std::string>> char_queue;

          public:
          simple_queue(const simple_queue&) = delete;
          simple_queue& operator=(const simple_queue&) = delete;

          uint32_t write(const char* const buff, const uint32_t size) noexcept
          {
          const uint32_t size_to_copy = std::min(max_msg_size, size);
          char_queue.emplace(buff, size_to_copy);
          return size_to_copy;
          }

          uint32_t read(char* const buff, const uint32_t size) noexcept
          {
          if (char_queue.empty())
          {
          return 0;
          }
          std::string& msg = char_queue.front();
          const uint32_t size_to_copy = std::min(msg, size);
          msg.copy(buff, size_to_copy, 0);

          char_queue.pop();
          return size_to_copy;
          }
          };


          EDIT:



          I forgot to mention, that now you should use a std::vector as backing of the queue as your are not storing a gargantuan array but rather a mall std::string.



          Note that it actually ends up being the same. The std::deque based std::array implementation is backed by a linked list, so each array ends up in a node of a linked list, which is kind of similar to the separate allocation of the std::string






          share|improve this answer











          $endgroup$









          • 2




            $begingroup$
            You should not use "EDIT tags"; they are only confusing and distracting for people who come to the question or answer for the first time. Edits happen all the time, and anyone interested can just click to see the whole post history.
            $endgroup$
            – Juho
            yesterday










          • $begingroup$
            Thanks, all of your points are valid. I have updated the implementation and after running benchmarks it is performing much better. However there is still something I would like to improve. With every .emplace(buff, size_to_copy) the allocator for std::string is called, I would like to get rid of allocation and have it use a pre allocated chunk of memory. I was under the impression it might be easier to do so with std::array and that's why I opted to use that instead of std::string.
            $endgroup$
            – Ali
            yesterday












          • $begingroup$
            @miscco BTW, I did not get why you've mentioned to use std::vector, you mean I should use a vector of chars?
            $endgroup$
            – Ali
            yesterday








          • 1




            $begingroup$
            @Ali std::queue is a container-adaptor. The second template argument it takes is the underlying container. Consequently, in the example i replaced the default container std::deque with std::vector
            $endgroup$
            – miscco
            yesterday










          • $begingroup$
            @Ali Regarding your first comment, you will most likely never get rid of all allocations, as the std array is allocated into a container node anyway. In fact it even better to allocate a potentially smaller string than always putting a gargantuan array into std::deque node
            $endgroup$
            – miscco
            yesterday














          2












          2








          2





          $begingroup$

          You are not allocating per se when when writing to the queue. std::array is backed by a plain C-array on the stack, that gets moved.



          So you only ever allocate depending on the underlying container the std::queue is based on. By default this is a std::deque.



          I do not really understand the need for the std::array in the type though. Why not just use a std::string and limit the size of it to 4096? There is even a constructor that does explicitely that string (const char* s, size_t n)



          Before I get to the Code there are some other things I would like to mention:




          1. why are you not useing std::copy instead of memcpy. The former works better with C++ and will in the end almost always end up as memcpy?


          2. You do not need to define the special member functions. In fact you have forgotten 2 of then, aka copy assignment and copy constructor. Why do I say forgotten? Because there is no way to tell. So If you want your queue to be move only then you should actually delete those special member functions you dont want.


          3. In your read function you never check whether the size you want to read is actually valid. Is that intendend? If so why? A std::array is not initialized so the memory in it that is not written by you will be random. You are not writing to it but you are copying it around. So you should actually take the minimum out of size and queue.front().size()


          4. std::string has a member function std::string::copy that copyies a certain amount of chars to a buffer (http://www.cplusplus.com/reference/string/string/copy/). I would suggest to use that for writing back to the buffer



          That leads me to the following:



          #include <string>
          #include <queue>
          #include <vector>

          class simple_queue
          {
          private:
          static constexpr uint32_t max_msg_size = 4096;
          std::queue<std::string, std::vector<std::string>> char_queue;

          public:
          simple_queue(const simple_queue&) = delete;
          simple_queue& operator=(const simple_queue&) = delete;

          uint32_t write(const char* const buff, const uint32_t size) noexcept
          {
          const uint32_t size_to_copy = std::min(max_msg_size, size);
          char_queue.emplace(buff, size_to_copy);
          return size_to_copy;
          }

          uint32_t read(char* const buff, const uint32_t size) noexcept
          {
          if (char_queue.empty())
          {
          return 0;
          }
          std::string& msg = char_queue.front();
          const uint32_t size_to_copy = std::min(msg, size);
          msg.copy(buff, size_to_copy, 0);

          char_queue.pop();
          return size_to_copy;
          }
          };


          EDIT:



          I forgot to mention, that now you should use a std::vector as backing of the queue as your are not storing a gargantuan array but rather a mall std::string.



          Note that it actually ends up being the same. The std::deque based std::array implementation is backed by a linked list, so each array ends up in a node of a linked list, which is kind of similar to the separate allocation of the std::string






          share|improve this answer











          $endgroup$



          You are not allocating per se when when writing to the queue. std::array is backed by a plain C-array on the stack, that gets moved.



          So you only ever allocate depending on the underlying container the std::queue is based on. By default this is a std::deque.



          I do not really understand the need for the std::array in the type though. Why not just use a std::string and limit the size of it to 4096? There is even a constructor that does explicitely that string (const char* s, size_t n)



          Before I get to the Code there are some other things I would like to mention:




          1. why are you not useing std::copy instead of memcpy. The former works better with C++ and will in the end almost always end up as memcpy?


          2. You do not need to define the special member functions. In fact you have forgotten 2 of then, aka copy assignment and copy constructor. Why do I say forgotten? Because there is no way to tell. So If you want your queue to be move only then you should actually delete those special member functions you dont want.


          3. In your read function you never check whether the size you want to read is actually valid. Is that intendend? If so why? A std::array is not initialized so the memory in it that is not written by you will be random. You are not writing to it but you are copying it around. So you should actually take the minimum out of size and queue.front().size()


          4. std::string has a member function std::string::copy that copyies a certain amount of chars to a buffer (http://www.cplusplus.com/reference/string/string/copy/). I would suggest to use that for writing back to the buffer



          That leads me to the following:



          #include <string>
          #include <queue>
          #include <vector>

          class simple_queue
          {
          private:
          static constexpr uint32_t max_msg_size = 4096;
          std::queue<std::string, std::vector<std::string>> char_queue;

          public:
          simple_queue(const simple_queue&) = delete;
          simple_queue& operator=(const simple_queue&) = delete;

          uint32_t write(const char* const buff, const uint32_t size) noexcept
          {
          const uint32_t size_to_copy = std::min(max_msg_size, size);
          char_queue.emplace(buff, size_to_copy);
          return size_to_copy;
          }

          uint32_t read(char* const buff, const uint32_t size) noexcept
          {
          if (char_queue.empty())
          {
          return 0;
          }
          std::string& msg = char_queue.front();
          const uint32_t size_to_copy = std::min(msg, size);
          msg.copy(buff, size_to_copy, 0);

          char_queue.pop();
          return size_to_copy;
          }
          };


          EDIT:



          I forgot to mention, that now you should use a std::vector as backing of the queue as your are not storing a gargantuan array but rather a mall std::string.



          Note that it actually ends up being the same. The std::deque based std::array implementation is backed by a linked list, so each array ends up in a node of a linked list, which is kind of similar to the separate allocation of the std::string







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited yesterday

























          answered yesterday









          misccomiscco

          3,467517




          3,467517








          • 2




            $begingroup$
            You should not use "EDIT tags"; they are only confusing and distracting for people who come to the question or answer for the first time. Edits happen all the time, and anyone interested can just click to see the whole post history.
            $endgroup$
            – Juho
            yesterday










          • $begingroup$
            Thanks, all of your points are valid. I have updated the implementation and after running benchmarks it is performing much better. However there is still something I would like to improve. With every .emplace(buff, size_to_copy) the allocator for std::string is called, I would like to get rid of allocation and have it use a pre allocated chunk of memory. I was under the impression it might be easier to do so with std::array and that's why I opted to use that instead of std::string.
            $endgroup$
            – Ali
            yesterday












          • $begingroup$
            @miscco BTW, I did not get why you've mentioned to use std::vector, you mean I should use a vector of chars?
            $endgroup$
            – Ali
            yesterday








          • 1




            $begingroup$
            @Ali std::queue is a container-adaptor. The second template argument it takes is the underlying container. Consequently, in the example i replaced the default container std::deque with std::vector
            $endgroup$
            – miscco
            yesterday










          • $begingroup$
            @Ali Regarding your first comment, you will most likely never get rid of all allocations, as the std array is allocated into a container node anyway. In fact it even better to allocate a potentially smaller string than always putting a gargantuan array into std::deque node
            $endgroup$
            – miscco
            yesterday














          • 2




            $begingroup$
            You should not use "EDIT tags"; they are only confusing and distracting for people who come to the question or answer for the first time. Edits happen all the time, and anyone interested can just click to see the whole post history.
            $endgroup$
            – Juho
            yesterday










          • $begingroup$
            Thanks, all of your points are valid. I have updated the implementation and after running benchmarks it is performing much better. However there is still something I would like to improve. With every .emplace(buff, size_to_copy) the allocator for std::string is called, I would like to get rid of allocation and have it use a pre allocated chunk of memory. I was under the impression it might be easier to do so with std::array and that's why I opted to use that instead of std::string.
            $endgroup$
            – Ali
            yesterday












          • $begingroup$
            @miscco BTW, I did not get why you've mentioned to use std::vector, you mean I should use a vector of chars?
            $endgroup$
            – Ali
            yesterday








          • 1




            $begingroup$
            @Ali std::queue is a container-adaptor. The second template argument it takes is the underlying container. Consequently, in the example i replaced the default container std::deque with std::vector
            $endgroup$
            – miscco
            yesterday










          • $begingroup$
            @Ali Regarding your first comment, you will most likely never get rid of all allocations, as the std array is allocated into a container node anyway. In fact it even better to allocate a potentially smaller string than always putting a gargantuan array into std::deque node
            $endgroup$
            – miscco
            yesterday








          2




          2




          $begingroup$
          You should not use "EDIT tags"; they are only confusing and distracting for people who come to the question or answer for the first time. Edits happen all the time, and anyone interested can just click to see the whole post history.
          $endgroup$
          – Juho
          yesterday




          $begingroup$
          You should not use "EDIT tags"; they are only confusing and distracting for people who come to the question or answer for the first time. Edits happen all the time, and anyone interested can just click to see the whole post history.
          $endgroup$
          – Juho
          yesterday












          $begingroup$
          Thanks, all of your points are valid. I have updated the implementation and after running benchmarks it is performing much better. However there is still something I would like to improve. With every .emplace(buff, size_to_copy) the allocator for std::string is called, I would like to get rid of allocation and have it use a pre allocated chunk of memory. I was under the impression it might be easier to do so with std::array and that's why I opted to use that instead of std::string.
          $endgroup$
          – Ali
          yesterday






          $begingroup$
          Thanks, all of your points are valid. I have updated the implementation and after running benchmarks it is performing much better. However there is still something I would like to improve. With every .emplace(buff, size_to_copy) the allocator for std::string is called, I would like to get rid of allocation and have it use a pre allocated chunk of memory. I was under the impression it might be easier to do so with std::array and that's why I opted to use that instead of std::string.
          $endgroup$
          – Ali
          yesterday














          $begingroup$
          @miscco BTW, I did not get why you've mentioned to use std::vector, you mean I should use a vector of chars?
          $endgroup$
          – Ali
          yesterday






          $begingroup$
          @miscco BTW, I did not get why you've mentioned to use std::vector, you mean I should use a vector of chars?
          $endgroup$
          – Ali
          yesterday






          1




          1




          $begingroup$
          @Ali std::queue is a container-adaptor. The second template argument it takes is the underlying container. Consequently, in the example i replaced the default container std::deque with std::vector
          $endgroup$
          – miscco
          yesterday




          $begingroup$
          @Ali std::queue is a container-adaptor. The second template argument it takes is the underlying container. Consequently, in the example i replaced the default container std::deque with std::vector
          $endgroup$
          – miscco
          yesterday












          $begingroup$
          @Ali Regarding your first comment, you will most likely never get rid of all allocations, as the std array is allocated into a container node anyway. In fact it even better to allocate a potentially smaller string than always putting a gargantuan array into std::deque node
          $endgroup$
          – miscco
          yesterday




          $begingroup$
          @Ali Regarding your first comment, you will most likely never get rid of all allocations, as the std array is allocated into a container node anyway. In fact it even better to allocate a potentially smaller string than always putting a gargantuan array into std::deque node
          $endgroup$
          – miscco
          yesterday


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216097%2fsimple-raw-buffer-queue-implementation%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Webac Holding Inhaltsverzeichnis Geschichte | Organisationsstruktur | Tochterfirmen |...

          What's the meaning of a knight fighting a snail in medieval book illustrations?What is the meaning of a glove...

          Salamanca Inhaltsverzeichnis Lage und Klima | Bevölkerungsentwicklung | Geschichte | Kultur und...