0

In the code I am working on, I need to do the following:

  1. Create a map where each value is buffer of fixed size
  2. Use memcpy to populate one element of one value of the map (that is, one element of an array that is itself a value of the map) with some locally defined object

The following code is a small example of the concept:

#include <iostream>
#include <map>
#include <cstring>

int main()
{
    struct hdr {
        int cpi_length = 42;
    } ;

    void* this_hdr = new hdr;
    std::map<int, hdr(*)[20]> SP;
    std::cout << sizeof(hdr) << std::endl; // "4"
    std::cout << sizeof(this_hdr) << std::endl; // "4"
    std::cout << sizeof(SP[0][0]); // "80"
    std::memcpy(SP[0][0], this_hdr, sizeof(hdr)); // "Error: access violation"
    std::cout << SP[0][0]->cpi_length;
    return 0;
}

This brings me to two problems: 1) how to resolve the runtime error when trying to use memcpy, and 2) once the error is resolved, how do I ensure that this code will do what I described it should do?

As shown with the commands sizeof, the instance of the struct being copied in is identical in size to the struct itself, and (apparently) is a lot smaller than the size of the array element it is being copied into. So why the access violation? There should be plenty of room to spare.

I know that it may seem silly why I would use memcpy in this instance, why would I use pointers for the buffer instead of a vector, etc. This is just a reproducible example, understand that in the actual code I am restricted to these implementation choices. For now, I am going off of the assumption that I am just making some simple mistake like mixing up the syntax when it comes to referencing/de-referencing pointers.

8
  • 3
    Pop quiz: SP[0] is a pointer to an array of 20 hdrs. Here's a trick question for you: in the shown code, where does SP[0] actually point to? This is a trick question because it's not pointing to anywhere. The shown code fails to initialize this pointer, so SP[0][0] results in demons flying out of your nose. You need to figure out where this should be pointing to, and adjust the code accordingly. Commented Sep 14, 2023 at 19:44
  • I explained at the top of my question what the code is intended to do, so I posted the question asking for how to "adjust the code accordingly" @SamVarshavchik Commented Sep 14, 2023 at 20:41
  • Code speaks louder than words. Commented Sep 14, 2023 at 20:48
  • 1
    @SamVarshavchik I verbally described what I want and then wrote a small, reproducible example of what I've attempted so far. What else could I do? Is there an etiquette of stack overflow I'm not familiar with? Commented Sep 14, 2023 at 20:49
  • 1
    @UpAndAdam: OP does not have an array of ten hdr*. OP has one uninitializedd pointer. Commented Sep 14, 2023 at 21:20

2 Answers 2

5

Create a map where each value is buffer of fixed size

That's not what you are doing. Here's the one test you forgot:

std::cout << sizeof(SP[0]); // How large is the actual element of the map?

Here's a map where each value is a buffer of a fixed size:

std::map<int, std::array<hdr, 20>> SP;
Sign up to request clarification or add additional context in comments.

14 Comments

When trying your implementation then trying to access SP[0][0] (the first element of the array indexed at 0 in the map) gives the syntax error: no operator "[]" matches these operands: std::array<hdr, 20U>[int]. Is there different syntax to access the array?
Did you include <array>? Also remember that SP[0][0] isn't a pointer anymore.
@NathanGoedeke If you can't use std::array, fake it out. All std::array is is a normal array inside a class with a couple support functions like operator []. You can knock one of your own out in a few minutes. As soon as you put the array in a structure, you can pass around the structure by value and it'll carry the array with it. With the extra support functions you'll hardly be able to tell the difference between it and a normal array. Side note: The answer is n.m.'s not mine.
@NathanGoedeke UpAndAdam looks to have that covered. But take his advice and don't do it.
@NathanGoedeke If you use pointers, they need to point to something, and you need to manage allocation of that something. Not recommended.
|
1

The other option if you really want to go with dynamic memory is quite simple. Just remember you also have to clean up after yourself, I would still strongly suggest using a std::array for the syntactical clarity and convenience. Because it is so much cleaner and dirty feeling I have also included that variant as well.

I think both of the non-std::array ways of allocating are pretty bad, I don't like using malloc in C++ and I also feel like having to reinterpret_cast the result of new is bad / not something I generally recall having to do. The std::array is much much cleaner, though a smart pointer would be even better.

And it always feels a little silly to me to use non smart pointers in the map because then you have to either keep a seperate container for all the memory ownership to make sure you delete it all (which is fairly common at least in placement new memory pool cases) or you have to wrap the class with your in inserter/deleter so that you make sure you destroy (destructor and free memory) any object you remove from the map. (again unless you delegate memory ownership to a secondary structure)

#include <iostream>
#include <map>
#include <cstring> // for memcpy
#include <array>

int main()
{
    struct hdr {
        int cpi_length = 42;
    };

    hdr* this_hdr = new hdr; // notice not using void* here
    std::map<int, hdr(*)[20]> SP; // ok each int points to an array of 20 hdr pointers.
    // for contrast
    std::map<int, *std::array<hdr, 20>> SP2;

    // ok lets fill in one of them:
    // the C styleish way (note this technically would also be a reinterpret cast to go from void * to hdr(*)[20] )
    SP[0] = (hdr (*)[20])malloc(sizeof(hdr)*20); //allocate the memory for the array of 20 hdr's
    // OR the C++ish way without std::array
    // Note I really don't like having to reinterpret_cast this
    // SP[0] = reinterpret_cast<hdr (*)[20]>(new hdr[20]);
    // and for contrast     
    SP2[0] = new std::array<hdr, 20>;

    std::memcpy(&SP[0][0], static_cast<void *>(this_hdr), sizeof(hdr)); // now copy it
    std::memcpy(&SP2[0][0], static_cast<void *>(this_hdr), sizeof(hdr)); // now copy it

    std::cout << SP[0][0]->cpi_length;
    std::cout << SP2[0][0]->cpi_length;

    //ok all done
    free(SP[0]);
    // OR if you used NEW ABOVE
    // delete [] SP[0];
    delete SP2[0];
    delete this_hdr;
    //destructor for SP will do the rest...
    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.