记忆移动制造一个地方垃圾

Memmove making one spot garbage?

本文关键字:一个 方垃圾 移动 制造 记忆      更新时间:2023-10-16

我正在使用memmovestd::string元素向右移动一个位置。目的地的第一个地点是唯一一个被搞砸并充满垃圾的地方。我正在使用memmove而不是strcpy因为我在需要模板的类中使用它。不过,当我有一个整数数组时,它工作正常。关于如何为字符串解决此问题的任何想法?

/**
 * @brief Shifts elements in the array to the right
 * @param newItem The insert position.
 */
template<class T>
void DynamicArray<T>::shiftElementsRight(uint newItem) {
    uint diff = _size - newItem;
    memmove(&(_array[newItem + 1]),
            &(_array[newItem]), sizeof(_array[0]) * diff);
}

我的主要

int main() {
    DynamicArray<string> array(1);
    string val1 = "val1";
    array.add(val1);
    string val2 = "val2";
    array.add(val2);
    // ... more additions ...

最后一个输出:

Sizeof: 8
Value is: val1
Value is: val11val3, val21
                            ����[val1, val2A����[val1, val2, val31val4, Aq�����[val1, val2, val3 val4, val5Q`r�#����[val1, val2, val3, val4, val5, val61val5, 1val6, Q"����[val1, val2, val3, al4, a
8s��p�hp��p�hq�(r�Xr�؄KC�؄KC�؄KC�1val7, a:����[val1, val2, val3, val4, val5, qF����[val1, val2, val3, val4, val5, val6]

当数组包含std::string对象时,memcpymemmove都是不可能的。原因是两者都在不应该篡改对象内部时篡改(C++对象的完整性由其构造函数/赋值运算符/析构函数/成员函数确保,除非您确切知道自己在做什么,否则不得手动修改其字节)。

正如已经建议的那样,使用一种考虑构造函数、赋值运算符和析构函数的方法(例如std::copy_backward),或者更好的是,摆脱那些遗留的 C 数组并使用适当的C++容器(如 vector)并使用容器的函数插入/删除项目。

换句话说,一旦你开始使用C++对象,你就必须开始编写C++,而不是"带有类的C"。

来自memcpy描述:

为了避免溢出,数组的大小由两个 目标和源参数应至少为字节数,并且 不应该重叠(对于重叠的内存块,memmove更安全 方法)。

换句话说,使用memmove。

就像这里的大多数人说的那样,您可以使用memmove而不是memcpy因为它可以处理重叠的范围。

但是,C++解决方案是使用 copy_backward ,它明确执行您的要求,并将在屏幕后面为您选择最快的复制方法。那看起来像这样:

std::copy_backward(std::begin(_array)+newItem, std::end(_array)-1, std::end(array));

这意味着您将从上一个到最后一个元素向后复制以放置 newItem,并从后面开始插入该元素。这显然可以处理这需要的重叠。可能是在屏幕后面使用了memmove或其他特定于平台的内存副本。

 SYNOPSIS
        #include <string.h>
        void *memcpy(void *dest, const void *src, size_t n);
 DESCRIPTION
        The  memcpy()  function  copies  n bytes from memory area src to memory
        area dest.  The memory areas must not overlap.  Use memmove(3)  if  the
        memory areas do overlap.

您的内存区域不得重叠,否则不会定义memcpy的行为。 您应该改用memmove

您不能将memcpy用于重叠范围,如库文档中所述:

7.21.2 复制函数

7.21.2.1 内存函数

2 memcpy 函数将 n 个字符从 s2 指向的对象复制到 s1 指向的对象中。如果在重叠的对象之间进行复制,则行为是未定义的

7.21.2.2 内存移动函数

2 memmove 函数将 s2 指向的对象中的 n 个字符复制到 S1 指向的对象。复制就像对象的 n 个字符一样发生 由 S2 指向的首先复制到一个由 n 个字符组成的临时数组中,该数组不 重叠 S1 和 S2 指向的对象,然后重叠 临时数组被复制到 S1 指向的对象中。

对于 POD 或简单初始化的类型,您可以使用 memmove(如上所述)或std::copy_backward(只要最后一个目标元素不在源范围内)

这个问题对memcpy-vs-memmove部分进行了更多讨论。

对于非平凡的类型,如std::string,不能使用memcpymemmove,而必须使用std::copystd::copy_backward