【问题标题】:_alloca and std::vector of const char*_alloca 和 std::vector 的 const char*
【发布时间】:2021-11-10 01:12:25
【问题描述】:

我对 _alloca 函数做了几次搜索,一般不推荐。 我将有一个动态更新的字符串数组,我必须经常对其进行迭代。 我希望在堆栈上分配每个字符串以尽可能减少未命中缓存。

使用 _alloca 我可以在堆栈上创建一个 char* 并将其放入向量中。 我的 char 将位于一个不会影响我的堆栈的向量中,并且我知道当我在堆栈上分配字符串时,这些字符串永远不会大到导致堆栈溢出。

在这种情况下使用它是不是一件坏事?

程序是否按照我的意愿执行?

#include <vector>
#include <cstring>

#ifdef  __GNUC__
# define _alloca(size) __builtin_alloca (size)
#endif /* GCC.  */

std::vector<const char*> vec;

void add(const char* message, int size) {
  char* c = (char*) _alloca (size * sizeof(char*));
  std::memcpy(c, message, sizeof(message));
  vec.push_back(c);
}

int main() {
  const char* c = "OK";
  for (int i = 0; i < 10; ++i) {
    add(c, 2);
  }
}

【问题讨论】:

  • 你的add 函数已经坏了,当add 退出时,存储在vec 中的指针将悬空
  • 我愿意打赌std::vector&lt;std::string&gt; 对你来说会表现得很好。您是否尝试过并测量了性能以知道它不是您需要的?另外,我认为这有 UB,因为_alloc 应该在add 返回后释放内存。
  • 它最终被破坏了因为内存是在堆栈上分配的。当函数退出时,堆栈会被“清除”。您如何确定std::string 导致缓存未命中?大多数实现都执行小字符串优化
  • 当在慢与正确、快与坏之间做出选择时,请选择慢与正确。
  • 你不能在没有额外分配的情况下复制它,因为std::vector 拥有的内存位于“其他地方”。您可以做的最接近的事情是 std::vector&lt;std::array&lt;char, SOME_MAX_SIZE&gt;&gt; 并在那里手动创建以 null 结尾的字节字符串,但这有其自身的缺点(例如:确定 SOME_MAX_SIZE 应该是什么)

标签: c++ string memory memory-management


【解决方案1】:

_alloca 分配的堆栈内存在调用_alloca 的函数返回时自动释放。指向它的指针被推到某个地方(特别是某个向量)这一事实并不能阻止该内存被释放(正如您提到的那样,您假设在 cmets 中会发生),这不是 C++ 的工作方式。 C++ 中没有“垃圾收集”。

因此,显示的代码最终存储了一个指向已释放堆栈内存的指针。一旦add() 返回,这会留下一个悬空指针,任何后续使用它都会导致未定义的行为。

换句话说:是的,“在这种情况下使用它是一件坏事”,因为显示的代码将不起作用。

这个特定的_alloca 调用还有其他几个主要问题,但这不是重点。即使这些问题得到正确解决,整个方法也会失败。

【讨论】:

  • 好吧,别无选择,只能继续使用 std::string。谢谢
  • @antho 总是有选择的。如果您事先知道字符串的大小,可以使用std::array 的向量。如果你不这样做,但你可以在这里允许动态分配,你可以使用你自己的不做动态内存管理的分配器。
猜你喜欢
  • 2021-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-07
  • 2021-06-02
  • 1970-01-01
相关资源
最近更新 更多