F
Francois Duranleau
Hi,
I am facing a situation where I would like to follow strict aliasing,
but, unless I misunderstand the standard, I can't find a solution
without sacrificing performance, memory size, etc.
The problem is as follows. Essentially, I have a runtime description
of a buffer's layout in memory. The information is essentially a set
of offset (in bytes) with type of data located at that offset. There
is an API I use that needs the data to be sent in that particular
layout. A common method of dealing with such a buffer is something
like this:
- Buffer is allocated like this:
char* buffer = new char[buffer_size];
- Assigning/querying data from that buffer is done with something like
this:
template < typename T >
void set_buffer_data(char* buffer, unsigned int offset, const T& data)
{
T* d = reinterpret_cast<T*>(buffer + offset);
*d = data;
}
template < typename T >
const T& get_buffer_data(const char* buffer, unsigned int offset)
{
const T* d = reinterpret_cast<const T*>(buffer + offset);
return *d;
}
I am volontarily simplifying things to better illustrate the problem,
so never mind alignment and type safety problems, and proper
initialization of the buffer's content with non-POD types.
Now, if I read the standard correctly (3.10-15), this is a violation
of strict aliasing because casting from char* to T* (T != char or
unsigned char) and then accessing the data via that pointer is not
allowed. But then, how can we handle this without sacrificing
performance and memory?
We could do memcpy, e.g.
template < typename T >
void set_buffer_data(char* buffer, unsigned int offset, const T& data)
{
memcpy(buffer + offset, &data, sizeof(T));
}
template < typename T >
void get_buffer_data(const char* buffer, unsigned int offset, T& data)
{
memcpy(&data, buffer + offset, sizeof(T));
}
and hope the compiler optimizes this well. But then, what about non-
PODs? And get_buffer_data now needs to return a copy all the times (I
could live with that, though, as most of the times, the return value
would be assigned to a non-reference variable anyways).
For the record, a concrete example for this problem is when dealing
with OpenGL's uniform buffers (I guess it would be similar with
D3D10+'s constant buffers). At runtime, you get a layout description
of a buffer, and you have to respect that layout to send the data.
I am facing a situation where I would like to follow strict aliasing,
but, unless I misunderstand the standard, I can't find a solution
without sacrificing performance, memory size, etc.
The problem is as follows. Essentially, I have a runtime description
of a buffer's layout in memory. The information is essentially a set
of offset (in bytes) with type of data located at that offset. There
is an API I use that needs the data to be sent in that particular
layout. A common method of dealing with such a buffer is something
like this:
- Buffer is allocated like this:
char* buffer = new char[buffer_size];
- Assigning/querying data from that buffer is done with something like
this:
template < typename T >
void set_buffer_data(char* buffer, unsigned int offset, const T& data)
{
T* d = reinterpret_cast<T*>(buffer + offset);
*d = data;
}
template < typename T >
const T& get_buffer_data(const char* buffer, unsigned int offset)
{
const T* d = reinterpret_cast<const T*>(buffer + offset);
return *d;
}
I am volontarily simplifying things to better illustrate the problem,
so never mind alignment and type safety problems, and proper
initialization of the buffer's content with non-POD types.
Now, if I read the standard correctly (3.10-15), this is a violation
of strict aliasing because casting from char* to T* (T != char or
unsigned char) and then accessing the data via that pointer is not
allowed. But then, how can we handle this without sacrificing
performance and memory?
We could do memcpy, e.g.
template < typename T >
void set_buffer_data(char* buffer, unsigned int offset, const T& data)
{
memcpy(buffer + offset, &data, sizeof(T));
}
template < typename T >
void get_buffer_data(const char* buffer, unsigned int offset, T& data)
{
memcpy(&data, buffer + offset, sizeof(T));
}
and hope the compiler optimizes this well. But then, what about non-
PODs? And get_buffer_data now needs to return a copy all the times (I
could live with that, though, as most of the times, the return value
would be assigned to a non-reference variable anyways).
For the record, a concrete example for this problem is when dealing
with OpenGL's uniform buffers (I guess it would be similar with
D3D10+'s constant buffers). At runtime, you get a layout description
of a buffer, and you have to respect that layout to send the data.