2

I know, I know. The question just screams "you shouldn't be in that situation!" but hear me out...

I have a game engine that performs the updates in one thread and the renders in another. The renders want to read the data from the previous frame while the update updates the data as it would be for the next frame.

So, to solve this I have a POD struct, mutable_data, that is everything in the object that can change (velocity, position, etc...) which I have two instances of inside the object, one const and the other not. At the end of one iteration of the game loop the non-const data will be the up-to-date data object and I want to then copy this over the const instance so that they are now equal and ready for the next iteration.

Is this possible?

I've drafted up an example program that hopefully makes it clear what I mean:

#include <iostream>

struct mutable_data
{
  int i = 1;
  bool j = true;
  char k = 'a';
};

struct my_data
{
  my_data() : constData() {} 

  int i() const { return constData.i; }
  bool j() const { return constData.j; }
  char k() const { return constData.k; }

  void set_i(int i) { data.i = i; }
  void set_j(bool j) { data.j = j; }
  void set_k(char k) { data.k = k; }

  void update() { constData = data; }

private:
  mutable_data const constData;
  mutable_data data;
};

int main()
{
  my_data d;
  std::cout << "i: " << d.i() << ", j: " << d.j() << ", k: " << d.k() << std::endl;

  d.set_i(10);
  d.set_j(false);
  d.set_k('z');

  std::cout << "i: " << d.i() << ", j: " << d.j() << ", k: " << d.k() << std::endl;
  std::cout << "===============" << std::endl;

  d.update();

  std::cout << "i: " << d.i() << ", j: " << d.j() << ", k: " << d.k() << std::endl;
}
11
  • 5
    why is the const one marked const, if it's not meant to remain constant? Commented Jan 30, 2014 at 20:05
  • Comment on your data structure: wouldn't it work better to keep two separate data trees with top level pointers that swap which is for update and which is for read? Rather than keep two sets of data inside each object. Commented Jan 30, 2014 at 20:05
  • @Adam because it is a const object. I don't want anything to ever play with it... except when it needs to be updated. I know I can just declare it not const, but it feels way more appropriate for it to be const in this situation. No? Commented Jan 30, 2014 at 20:08
  • And then updates might look like update->obj[index].position = read->obj[index].position + read->obj[index].delta or similar. Commented Jan 30, 2014 at 20:08
  • 2
    @Sam: "because it is a const object. I don't want anything to ever play with it... except when it needs to be updated" -- you never want any object to be modified except when it's supposed to be modified. That doesn't mean every object should be const ;-) constData is a private member of its class and the only code in the class that modifies it is in update(). That's enough to enforce the constraint that only update() modifies it. Provided your classes are small and focussed, there is no practical danger of you accidentally writing code to modify it elsewhere. Commented Jan 30, 2014 at 20:40

2 Answers 2

4

Use accessors for your two data structures, one for the current (const) one and another for the upcoming one.

mutable_data & currentData() { return *currentPtr; }
const mutable_data & upcomingData() { return *upcomingPtr; }

void update() { std::swap(currentPtr, upcomingPtr); }
Sign up to request clarification or add additional context in comments.

3 Comments

Swapping wouldn't work I don't think... doesn't it have to be a copy? Say currentData is on frame 10, upcomingData is now on frame 11. So, when you swap, upcoming goes back a frame to 10 and yet we're on frame 11 and frame 12's data is about to be written even though frame 11's data is not there. Does that make sense? Sorry I find it hard to explain this! :)
@Sam you can do a copy too if you want, you didn't show enough logic to know if it was necessary. The point is that neither pointer is const so you can do anything at that point - the only restrictions are on the consumers of currentData and upcomingData.
I see, yeah I think you're right -- that would be the best way to go. Thanks!
2

This is a very interesting question. I think what you getting at is the issue with data race when implemented under conditions suitable for concurrency.

As discussed in a separate question, one possible way to manipulate what you want to be const is to modify the variable as mutable.

Of course, in order to accomplish this end, the struct would have to be redesigned. Having a const method to initialize the said variable will enable you to lock-in the value you want.

In addition to the keyword mutable, you should think about using const_cast to recast your variable.

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.