0

I am writing a program on a hotel reservation system and have declared a struct Room as follows:

struct Room {
bool isavailable;
bool ispaid;
string customer;
string date;
};

I use a variable read from an input file to create an array of n structs which is all the rooms in the hotel.

struct Room* rooms = new Room[numOfRooms];

I then create the shared memory space and attach it, but when I try to access it after, it doesn't seem to work.

//creates shared memory space
if((shmid = shmget(shmkey, 1000, IPC_CREAT | 0666)) < 0) {
    perror("Failed to allocate shared mem");
    exit(1);
}

//attaches shared memory to process
Room* shared_memory;
shared_memory = (Room* ) shmat(shmid, NULL, 0);
if(!shared_memory) {
    perror("Error attaching");
    exit(0);
}

struct Room *PTR = rooms; //temp pointer to rooms array
cout << "test: " << rooms[1].customer << endl; //print before storing in shared memory
rooms = (struct Room*) shared_memory+sizeof(int); //places rooms array in shared memory
delete [] PTR; //deletes the memory location where rooms was stored before being in shared memory
cout << "test: " << rooms[1].customer << endl; //print after storing in shared mem

As you can see I have a cout statement before moving rooms into shared memory which prints the correct thing, but the after cout is empty. Any help would be greatly appreciated, thanks.

Bzm10823
  • 3
  • 3
  • 3
    The `std::string` objects allocate their memory dynamically of the heap. The string data itself will not be in the shared memory, only the pointers to the memory. Using dynamic structures and data of any kind is non-trivial with shared memory (and IPC in general). – Some programmer dude Nov 13 '18 at 08:42
  • You are not moving `rooms` array into shared memory. Moreover, in C++, there is no way how to move objects in memory (you can copy their byte representations but only for _trivially-copyable_ types, which is not your case because of `string` member variables). What you can is to move contents of objects, but this requires their construction (in uninitialized memory) by using move constructor and placement-new syntax. Even then, in case of long strings, their characters will remain in the (not-shared) heap. You will only share `string` objects themselves, not stored strings. – Daniel Langr Nov 13 '18 at 08:46
  • @DanielLangr so what if I were to rewrite the string member variables as chars? – Bzm10823 Nov 13 '18 at 08:53
  • @Bzm10823 If you use a char array of some predefined size, then it its ok (such as `char customer[100];`. If you use a dynamically allocated char array, then you have the very same problem as with `std::string`. – Daniel Langr Nov 13 '18 at 08:55

1 Answers1

1

rooms = (struct Room*) shared_memory+sizeof(int); //places rooms array in shared memory

This line does not do what your comment says. First, shared_memory is already declared as Room* shared_memory so the cast is unnecessary. Adding sizeof(int) (let's assume that is 4) to a pointer will make the pointer point to the 4th such element, that is if shared_memory was pointing to the first element of a Room arr[N] array, the expression shared_memory + i is equal to &arr[i]. In this case, shared_memory+sizeof(int) is a pointer to the 4th (or sizeof(int)'th) element -- or rather where that element would be in the shared_memory because you just created the shared memory and haven't put any actual Rooms in there yet.

Finally, rooms = ... just assigns a value to the pointer. So now the rooms variable (which is a pointer, just a number basically) points to the place where the 4th Room object in the shared_memory array would be. It's not copying the array created with new Room[numOfRooms] or anything like that.

See also: How do pointer to pointers work in C?

What you want to do is copy the objects into shared memory. For that in general you could use std::copy like so:

std::copy(&rooms[0], &rooms[numOfRooms], shared_memory);

But the problem will be that std::string contains a pointer to a char array which you can assume to be allocated with new char[length_of_string]. (This is a simplified version of the truth, but enough for this.) The std::copy above will not move this internal array into shared memory, therefore it will not work if you map the shared memory in another process and access the string data. (You might read memory garbage or you might segfault when trying to access unmapped memory.) To solve this, you need to use an allocator type that can allocate from the shared memory, or store strings inline with something like a struct ShortString{ char data[/*max length*/ 20]; }. You'll want to search for or post another question if you need help with that.

palotasb
  • 4,108
  • 3
  • 24
  • 32
  • so I got rid of the string members from the struct and replaced the rooms = (struct Room*) shared_memory+sizeof(int); line with the copy you provided which seems to work. I'm guessing it is now fully accessing the structs from the shared memory? I am going to be using this with semaphores so multiple child processes can edit the structs without race conditions – Bzm10823 Nov 13 '18 at 09:25