0

I need a function that can take a vector of any one of float, int, double or short. It should then copy all the data in that vector into a new vector of char*.

Here my attempt. This is the first time I ever had to use memcpy so I don't know what I am doing.

#include <vector>
#include <memory>


std::vector<float> vertices = { 0.0, 0.1, 0.2, 0.3, 0.4 };

std::unique_ptr<std::vector<char*>> buffer = std::make_unique<std::vector<char*>>();
template<class Type>
void SetVertices(const std::vector<Type>& v)
{
    buffer->clear();
    buffer->resize(v.size() * sizeof(Type));
    memcpy(buffer.get(), v, v.size() * sizeof(Type));
}

int main()
{
    SetVertices(vertices);
} 

Here is the error message:

error C2664: 'void *memcpy(void *,const void *,size_t)': cannot convert argument 2 from 'const std::vector<float,std::allocator>' to 'const void *'

wohlstad
  • 12,661
  • 10
  • 26
  • 39
Cool_Cornflakes
  • 315
  • 2
  • 13
  • 1
    `memcpy` takes pointers, so you need to get a pointer to `v`'s data: `memcpy(buffer.get(), v, v.size() * sizeof(Type));` -> `memcpy(buffer.get(), v.data(), v.size() * sizeof(Type));` – NathanOliver Oct 19 '22 at 12:51
  • @NathanOliver Thank you. That seems to have solved that problem. But now i am getting a read access violation exception. – Cool_Cornflakes Oct 19 '22 at 12:53
  • 1
    Think very hard about this: does `vector` makes sense to you? Do you really want a vector of character pointers? Where are they going to point to, and how would a `memcpy` into it set this up? – Sam Varshavchik Oct 19 '22 at 12:54
  • 1
    `buffer.get()` needs to be changed to `buffer->data()` as you want a pointer to the data of the vector `buffer` points to but that still wont work. What buffer should be is a `std::vector buffer;` – NathanOliver Oct 19 '22 at 12:55
  • @SamVarshavchik I just want a generic store of bytes. Is char* not a good choice? – Cool_Cornflakes Oct 19 '22 at 12:55
  • `buffer` -- where is this set to point to anything? I see it declared, but that's it. Where is the call to `std::make_unique` or similar? – PaulMcKenzie Oct 19 '22 at 12:55
  • @PaulMcKenzie Oh sorry yes that is initialized using make unique – Cool_Cornflakes Oct 19 '22 at 12:57
  • what are you intending to do with this "generic store of bytes" once you have created it? – Neil Butterworth Oct 19 '22 at 12:58
  • It's a terrible choice. It makes no sense, whatsoever. It is not a "generic store of bytes". It's a "generic store of pointers to bytes somewhere else". And, in fact, looking at the shown code, if, say, for example, you have one POD that's 40 bytes long you're not going to get a vector that takes up 40 bytes of memory, but a vector that takes up `40*sizeof(char *)` memory, or either 160 or 320 bytes of memory, depending on your platform. Does that make sense to you? – Sam Varshavchik Oct 19 '22 at 12:58
  • @NeilButterworth It is an opengl vertex buffer – Cool_Cornflakes Oct 19 '22 at 13:00
  • May I suggest going back to basics and read a few [good books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). You clearly don't have your basic C++ knowledge down yet. – Jesper Juhl Oct 19 '22 at 13:02
  • A simple buffer of bytes (for e.g. opengl vertex buffer) can be: `std::vector`, or `std::vector` (No need for smart pointers). – wohlstad Oct 19 '22 at 13:04
  • @Cool_Cornflakes The question you asked is not actually the problem you're having. All those comments are correct -- a `memcpy` into a `vector`, even if done "correctly", will not yield what you think it does. You are taking the `double`'s binary representation, and turn that sequence of bits into a *pointer*, which will be pointing to [undefined]. You will get into *all* kinds of trouble when you're working on that result. Open up your question: "How do I get the binary representations of a vector of doubles?" – DevSolar Oct 19 '22 at 13:06
  • `memcpy(&(buffer->at(0)), &v[0], v.size() * sizeof(Type));` if had to using `uniqe_ptr` – Xin Cheng Oct 19 '22 at 13:13

1 Answers1

2

There are a couple issue with your code. First is that memcpy takes a pointer to the data you want copied and to the location you want the data copied to. That means you can't pass v to memcpy but need to pass v.data() so you get a pointer to the elements of the vector.

The second issue is that buffer has the wrong type. You want to store your data as bytes, so you want to store it in a char buffer. A std::vector<char*> is not a byte buffer but a collection of pointers to potential buffers. What you want is a std::vector<char> which is a single byte buffer. Making those changes gives you

#include <vector>
#include <memory>
#include <cstring>

std::vector<float> vertices = { 0.0, 0.1, 0.2, 0.3, 0.4 };

std::vector<char> buffer;
template<class Type>
void SetVertices(const std::vector<Type>& v)
{
    buffer.clear();
    buffer.resize(v.size() * sizeof(Type));
    std::memcpy(buffer.data(), v.data(), v.size() * sizeof(Type));
}

int main()
{
    SetVertices(vertices);
} 

Live example

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • `unsigned char` or `uint8_t` would be a better representation of byte data than `char`. You *could*, conceivably, write each indivitual `Type`'s binary representation into a separate `vector`, ending up with a `vector>` -- closer representing OP's approach. – DevSolar Oct 19 '22 at 13:11
  • @DevSolar Thank you. You are right, I have decided to use std::uint8_t instead of char. – Cool_Cornflakes Oct 19 '22 at 13:15
  • `buffer.clear();` isn't necessary, but probably doesn't matter – Caleth Oct 19 '22 at 13:18
  • Or even [std::byte](https://en.cppreference.com/w/cpp/types/byte), in C++17 or later – Nathan Pierson Oct 19 '22 at 14:03