C ++中的共享内存缓冲区,不违反严格别名规则 [英] Shared memory buffers in C++ without violating strict aliasing rules

查看:143
本文介绍了C ++中的共享内存缓冲区,不违反严格别名规则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力实现共享内存缓冲区,而不破坏C99的严格别名规则。


假设我有一些代码来处理一些数据,需要一些'scratch'内存来操作。我可以像下面这样写:

I am struggling with implementing a shared memory buffer without breaking C99's strict aliasing rules.

Suppose I have some code that processes some data and needs to have some 'scratch' memory to operate. I could write it as something like:

void foo(... some arguments here ...) {
  int* scratchMem = new int[1000];   // Allocate.
  // Do stuff...
  delete[] scratchMem;  // Free.
}

然后我有另一个函数做一些其他的东西, :

Then I have another function that does some other stuff that also needs a scratch buffer:

void bar(...arguments...) {
  float* scratchMem = new float[1000];   // Allocate.
  // Do other stuff...
  delete[] scratchMem;  // Free.
}

问题是foo()和bar并且在整个地方具有堆分配在性能和存储器碎片方面可能是相当不好的。一个明显的解决方案是一次性分配一个大小合适的共享内存缓冲区,然后将其作为参数BYOB样式传递给foo()和bar():

The problem is that foo() and bar() may be called many times during operation and having heap allocations all over the place may be quite bad in terms of performance and memory fragmentation. An obvious solution would be to allocate a common, shared memory buffer of proper size once and then pass it into foo() and bar() as an argument, BYOB-style:

void foo(void* scratchMem);
void bar(void* scratchMem);

int main() {
  const int iAmBigEnough = 5000;
  int* scratchMem = new int[iAmBigEnough];

  foo(scratchMem);
  bar(scratchMem);

  delete[] scratchMem;
  return 0;
}

void foo(void* scratchMem) {
  int* smem = (int*)scratchMem;
  // Dereferencing smem will break strict-aliasing rules!
  // ...
}

void bar(void* scratchMem) {
  float* smem = (float*)scratchMem;
  // Dereferencing smem will break strict-aliasing rules!
  // ...
}



我想我现在有两个问题:

- 如何实现一个共享的共享临时内存缓冲区,没有违反混叠规则?

- 即使上述代码违反严格的别名规则,没有对别名进行伤害。


I guess I have two questions now:
- How can I implement a shared common scratch memory buffer that is not in violation of aliasing rules?
- Even though the above code does violate strict aliasing rules, there is no 'harm' being done with the alias. Therefore could any sane compiler generate (optimized) code that still gets me into trouble?

感谢

推荐答案

其实,你写的不是严格的别名冲突。

Actually, what you have written is not a strict aliasing violation.

C ++ 11 spec 3.10.10说:

C++11 spec 3.10.10 says:


如果程序试图通过除了
类型之外的glvalue访问对象的存储值,则行为未定义

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined

因此,导致未定义行为的事情是访问存储的值,而不仅仅是创建一个指向它的指针。您的示例不违反任何内容。它需要做下一步:float badValue = smem [0]。 smem [0]从共享缓冲区获取存储的值,创建一个别名冲突。

So the thing that causes the undefined behavior is accessing the stored value, not just creating a pointer to it. Your example does not violate anything. It would need to do the next step: float badValue = smem[0]. smem[0] gets the stored value from the shared buffer, creating an aliasing violation.

当然,你不会在设置前捕获smem [0]它。你要先写它。分配到同一个内存不会访问存储的值,所以没有ailiasing然而,它是非法的写在一个对象的顶部,而它仍然活着。为了证明我们是安全的,我们需要从3.8.4开始的对象生命周期:

Of course, you aren't about to just grab smem[0] before setting it. You are going to write to it first. Assigning to the same memory does not access the stored value, so no ailiasing However, it IS illegal to write over the top of an object while it is still alive. To prove that we are safe, we need object lifespans from 3.8.4:


程序可以通过重用对象占用的存储器或
显式调用具有非平凡析构函数的类类型的对象的析构函数。对于具有非平凡析构函数的类类型的对象
,程序不需要在对象占用的存储被重用或释放之前显式地调用析构函数
; ... [继续关于不调用析构函数的后果]

A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; ... [continues on regarding consequences of not calling destructors]

你有一个POD类型,声明int对象都在它们的生命周期的末尾,我使用浮空的空间。然后,您可以重复使用浮动空间,并且不会发生别名冲突。

You have a POD type, so trivial destructor, so you can simply declare verbally "the int objects are all at the end of their lifespan, I'm using the space for floats." You then reuse the space for floats, and no aliasing violation occurs.

这篇关于C ++中的共享内存缓冲区,不违反严格别名规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆