【问题标题】:Segmentation fault when try to copy float vector of large size through memcpy尝试通过 memcpy 复制大尺寸浮点向量时出现分段错误
【发布时间】:2020-06-03 11:13:12
【问题描述】:

我正在尝试通过 memcpy 将浮点向量复制到 void* 变量中。如果向量大小小于 3000,则下面的代码可以正常工作。但是当尝试复制大小大于 3000 的向量时,我遇到了分段错误。

  void* process(std::string datatype) {
  //  given datatype will decide the dataype of vec.
  const uint64_t VEC_COUNT = 10; // vector size
  const uint64_t VEC_SZ = VEC_COUNT * sizeof(float);
  std::vector<float> float_vec;
  float_vec.reserve(VEC_COUNT);
  for (unsigned int i = 0; i < VEC_COUNT; ++i) {
    float val = (float)(rand() % 100) / 3.0f;
    float_vec.push_back(val);
  }

  void* data = nullptr;
  data = malloc(VEC_SZ);
  if (data == nullptr) {
    throw std::invalid_argument("Could not allocate memory for data!");
  }
  memcpy(data, &float_vec, VEC_SZ);
  }
 return data;
}

int main() {
 VEC_COUNT = 10; //will be same as in upper method
 void* data = process("float");
 std::vector<float> &k =
    *(static_cast<std::vector<float>*>(data));
  for (unsigned int i = 0; i < VEC_COUNT; ++i) {
    std::cout << "k[i] = " << k[i] << " , float_vec[i] = "
      << k[i] << std::endl;
}

在 memcpy 之前,我使用 malloc 来分配内存。 malloc 没有给出任何类型的分段错误,但 memcpy 不能正常工作。 当我使用 gdb 和回溯分段错误运行此代码时,出现以下错误

__memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:249

任何帮助将不胜感激。谢谢

【问题讨论】:

  • 这似乎是XY problem。请说明您真正想要实现的目标。
  • void* data = process("float")data 指向未知 大小的浮点值之后,您至少需要第二个参数,该参数将包含data 指向的值的数量.
  • 是的,我知道我需要这些信息。现在我正在尝试不同的东西,这就是为什么在“过程”方法和外部世界中硬编码大小的原因。\
  • @Hasnain 您不能将 float 元素的动态数组转换为向量。那是不可能的。要么将其用作数组 (data[i]),要么创建一个新向量并将数组中的元素复制到其中。顺便说一句,编辑后,代码将无法编译。 float_vecmain 中不存在。
  • @Hasnain 即使在编辑之后,也不清楚为什么需要一个普通的动态数组。为什么不简单地从process 函数返回向量?

标签: c++ memory memory-management


【解决方案1】:
memcpy(data, &float_vec, VEC_SZ);

这是行不通的,memcpy 只能用于 普通可复制 类型,std::vector 不是。

您可能想要的是:

memcpy(data, float_vec.data(), VEC_SZ);

此外,这个:

std::vector<float> &k =
   *(static_cast<std::vector<float>*>(data));

是完全非法的。在data 指向的地址上没有std::vector&lt;float&gt; 类型的对象。

【讨论】:

  • 如果 memcpy 仅适用于可简单复制的类型,那么为什么当向量的大小在 1-3000 范围内时以下行可以正常工作 ``` memcpy(data, &float_vec, VEC_SZ); ```
  • @Hasnain 它不能正常工作。它可以做anything,而你的fine 就是其中之一。
  • 我尝试了你的建议,但是当我尝试使用“std::vector &float_vec = *(static_cast<:vector>*> (data));",尝试按索引访问其值时出现分段错误。 @丹尼尔
  • @Hasnain 我说过你不能那样做。
  • 然后在(更新)memcpy 之后只需 return data;。然后为什么要定义向量引用k?为什么static_cast
【解决方案2】:

向量只是一个“信封”对象,它包含一个指向实际存储元素的动态分配内存的指针。因此,如果您获取矢量对象本身的地址,那么您获取的是“信封”的地址,而不是存储的第一个元素的地址。因此,您很可能会超出“信封”的范围,这是未定义的行为;所以它可能会以 100 的大小崩溃,也可能是它不会以 10000 的大小崩溃,而是做其他事情。至少它不会按预期复制实际元素。

要访问向量实际存储元素的内存,请使用其成员函数data()。所以下面的命令应该可以完成这项工作:

memcpy(data, float_vec.data(), VEC_SZ);

【讨论】:

  • 谢谢。我尝试了您的建议,并且在 memcpy 上没有分段错误。但现在给我错误将数据转换回浮点向量。
  • @Hasnain 为什么要把复制到data的数据转回向量???
【解决方案3】:

向量不是简单可复制的。在它们上使用memcpy 具有可能未定义的未指定行为。不要这样做。此外,在 C++ 中无需使用malloc

要复制一个向量,这是一个有效的解决方案:

std::vector<float> k = float_vec;

我有可以返回任何类型向量的方法,但我不想使用模板。

返回std::any

【讨论】:

  • 感谢您的回答。但在我的问题中,我需要将所有数据复制到一个 void* 中。
  • @Hasnain 您不能将数据复制到void*void* 只能指向数据。 void* 可以指向向量中存储的数据。
  • 有道理。但在我的问题中,我需要复制 void* 变量中的数据并从方法返回。如果我只是将指向数据的指针分配给 void*,当我超出方法范围时,数据将被删除。
  • @Hasnain 返回向量。
  • @Hasnain 如果调用者不知道类型,它如何使用数据?
猜你喜欢
  • 1970-01-01
  • 2018-06-11
  • 2021-08-05
  • 2011-01-06
  • 1970-01-01
  • 2014-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多