0

Here is my code:

size_t const header_length = 8;
size_t const body_size_b = 8;

ServerOpcode opc;
opc = ServerOpcode::SMSG_LOGIN_REQUEST_RESPONSE_TEST;
std::string header = std::to_string(opc);
flatbuffers::FlatBufferBuilder builder;
auto name = builder.CreateString("Orc MONSTER");
auto accountRole = Vibranium::CreateAccountRole_Packet(builder,1,name);
builder.Finish(accountRole);
size_t size = builder.GetSize();
uint8_t *buf = builder.GetBufferPointer();

std::array<char, header_length + body_size_b> buffer{};
std::copy(header.begin(), header.end(), buffer.begin());
std::copy(std::to_string(size).begin(), std::to_string(size).end(), buffer.begin() + header_length);
std::cout << "Size of buff before memcpy" << buffer.size() << std::endl;
memcpy(&buffer+size, &buf, size);
std::cout << "Size of buff after memcpy" << buffer.size() << std::endl;

The output when I run this code gives me:

Size of buff before memcpy16
Size of buff after memcpy16

That means I haven't copied buf into buffer. Why is that? How can I unify header, size and buf all in one std::array<char> ?

I want to do that because I want to send them all three in specific sequence with Boost ASIO.

Venelin
  • 2,905
  • 7
  • 53
  • 117
  • What makes you think that you didn't copy `buf` into `buffer`? The size of `buffer` is `header_length + body_size_b` i.e. 16 and that's exactly what you are printing – Mike van Dyke Sep 23 '20 at 13:09
  • Yea but I get error when I try `size_t wholeSize = size + header_length + body_size_b;std::array buffer{};` saying `Non-type template argument is not a constant expression` – Venelin Sep 23 '20 at 13:10
  • You can't change size of std::array. It will always be the same as declared: std::array. – Vasilij Sep 23 '20 at 13:10
  • I don't see any calls to functions that changes a container's size, even if you used a resizable container. – PaulMcKenzie Sep 23 '20 at 13:11
  • @PaulMcKenzie I haven't, how can I change the size of it? – Venelin Sep 23 '20 at 13:11
  • @VenelinVasilev You get that error because the second template argument of `std::array` has to be a constant expression, e.g. `const size_t wholeSize = ...` – Mike van Dyke Sep 23 '20 at 13:14
  • Still if I do `const size_t wholeSize = size + header_length + body_size_b;` I get the same error @MikevanDyke – Venelin Sep 23 '20 at 13:15
  • @VenelinVasilev `size` is not constant. – PaulMcKenzie Sep 23 '20 at 13:16
  • Array sizes are set at compile time and cannot be changed. You're looking for [`std::vector`](https://en.cppreference.com/w/cpp/container/vector). I highly recommend reading the documentation and performing a few experiments to familiarize yourself with its use. C++ is unforgiving to those who don't know the details. – user4581301 Sep 23 '20 at 13:16
  • if I go `size_t const wholeSize = header_length + body_size_b;` it works, however if I go `size_t const wholeSize = size + header_length + body_size_b;` it fires the same error `Non-type template argument is not a constant expression` why is that ? – Venelin Sep 23 '20 at 13:16
  • [I don't](https://godbolt.org/z/KcYqoM). Can you post a minimal example? – Mike van Dyke Sep 23 '20 at 13:16
  • `std::vector` instead of `std::array` ? @john Can you make an answer with vector example so I can accept it ? – Venelin Sep 23 '20 at 13:17
  • 1
    @VenelinVasilev The second template parameter has to be a [constant expression](https://en.cppreference.com/w/cpp/language/constant_expression), i.e. the compiler needs to know it's value at compile time. `size` is determined at runtime, which is why you cannot use it. – Mike van Dyke Sep 23 '20 at 13:19
  • @MikevanDyke is then a vector a good replacement of array ? – Venelin Sep 23 '20 at 13:21
  • 1
    Off topic but `std::copy(std::to_string(size).begin(), std::to_string(size).end(), ...` will result in undefined behaviour since `std::to_string` returns an `std::string` by value meaning the two iterators you pass to `std::copy` are from different containers. – G.M. Sep 23 '20 at 14:05

3 Answers3

2

If you don't know size_t size in advance it is best to use a vector to copy buf into a new buffer:

#include <vector>
#include <iterator>

// ... 
size_t size = builder.GetSize();
uint8_t *buf = builder.GetBufferPointer();

std::vector<uint8_t> buffer;
std::copy(header.begin(), header.end(), std::back_inserter(buffer))
// Don't know what you are intending with the following line
// std::copy(std::to_string(size).begin(), std::to_string(size).end(), buffer.begin() + header_length); 
std::copy(buf, buf + size, std::back_inserter(buffer));

std::back_inserter will fill up the vector with the entries of header and buf on the fly, i.e. during the copy procedure, so that you don't need to reserve memory for the vector in advance.

Mike van Dyke
  • 2,724
  • 3
  • 16
  • 31
1

std::array have a fixed size. period. It does not depend on how many elements you put inside.

So here you declare std::array<char, header_length + body_size_b> buffer{};

So you declare an array of size header_length + body_size_b and this size won't change, no matter what you do in the memory.

buffer.size() will always return header_length + body_size_b and in your case it is equal to 16.

If you want a container with variable size, use std::vector, and check the methods push_back, resize, reserve...

EDIT

It's probably something like that you want to do:

// Create a vector of the same size as the string header, and filled with the string header.
std::vector<char> buffer(header.begin(), header.end());

size_t buf_size = builder.GetSize();

// Resize the buffer vector so it can contain the header plus the content of buf
buffer.resize(buffer.size() + buf_size);

// Copy buf_size elements from the buf adress
std::copy(buf, buf + buf_size, buffer.begin() + buffer.size());
Pierre Baret
  • 1,773
  • 2
  • 17
  • 35
  • Thank you! However can you please show me how can I put `buf` into `std::vector buffer{};` ? – Venelin Sep 23 '20 at 13:27
  • After I declare `buffer` i do `size_t const wholeSize = size + header_length + body_size_b;buffer.resize(wholeSize);` And then I do `std::copy(header.begin(), header.end(), buffer.begin());` and `std::copy(std::to_string(size).begin(), std::to_string(size).end(), buffer.begin() + header_length);` however I don't know ho to include `buf` as the third element. How can I do that ? – Venelin Sep 23 '20 at 13:29
  • What is buffer size ? – Pierre Baret Sep 23 '20 at 13:32
  • `buffer.resize(wholeSize);` or you mean what is the size of `buf` ? – Venelin Sep 23 '20 at 13:33
  • I mean the size of buf, the number of chars that you want to store in a container after the header if I understand well – Pierre Baret Sep 23 '20 at 13:34
  • message sequence is. 1header2bodysize3body – Venelin Sep 23 '20 at 13:35
  • Size of `buf` is `size_t size = builder.GetSize();` – Venelin Sep 23 '20 at 13:36
  • `GetSize()` method on builder `Returns an `uoffset_t` with the current size of the buffer.` – Venelin Sep 23 '20 at 13:37
  • check out the dit in my answer – Pierre Baret Sep 23 '20 at 13:45
  • Hah - I overwrote the wrong members in my example for you. It should be std::vector destinationBuffer(size + 1, 0); std::copy(buf, buf + size, destinationBuffer.begin()); You could also just do std::vector destinationBuffer(buf, buf + size); I would recommend you rename your objects for more clarity so instead of "size_t size" use something like "size_t orcSize" and instead of "uint8_t* buf" use something like "uint8_t* orcBuffer" That will help with maintenance and readability. – GTAE86 Sep 23 '20 at 13:55
  • 2
    `std::vector::reserve` and a [`std::back_inserter`](https://en.cppreference.com/w/cpp/iterator/back_insert_iterator) can be handy as well. – user4581301 Sep 23 '20 at 14:06
0

The problem is the sizeof on an std::array as you can read from this answer Is the size of std::array defined by standard or better from this one What is the sizeof std::array<char, N>? [duplicate].

Zig Razor
  • 3,381
  • 2
  • 15
  • 35