Memmove制作一个现场垃圾?

时间:2013-10-18 07:05:12

标签: c++

我正在使用memmovestd::string元素向右移动一个点。目的地的第一个地方是唯一被弄乱并充满垃圾的地方。我使用的是memmove而不是strcpy,因为我在需要模板的类中使用它。当我有一系列的int时,它工作正常。关于如何解决这个问题的任何想法?

/**
 * @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]

5 个答案:

答案 0 :(得分:6)

当您的数组包含memcpy个对象时,memmovestd::string都不可能。原因是当它们不应该篡改对象的内部时(C ++对象的完整性由其构造函数/赋值运算符/析构函数/成员函数确保,您必须修改其字节除非你确切知道你做了什么,否则请手动。

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

换句话说,一旦你开始使用C ++对象,你就必须开始编写C ++,而不再是“C with classes”。

答案 1 :(得分:2)

来自memcpy description

  

为了避免溢出,两者都指向了数组的大小   目的地和源参数,至少应为num个字节,和   不应该重叠(对于重叠的内存块,memmove是更安全的   方法)。

换句话说,

使用memmove

答案 2 :(得分:1)

 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代替。

答案 3 :(得分:1)

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

  

7.21.2复制功能

     

7.21.2.1 memcpy函数

     

...

     

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

     

7.21.2.2 memmove功能

     

...

     

2 memmove函数将s2指向的对象中的n个字符复制到   s1指向的对象。复制就像对象中的n个字符一样   由s2指向的第一个被复制到n个字符的临时数组中   重叠s1和s2指向的对象,然后重写n个字符   临时数组被复制到s1指向的对象中。

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

This question更多地讨论了memcpy-vs-memmove部分。

对于std::string等非平凡类型,您无法使用memcpy memmove,但必须使用std::copystd::copy_backward

答案 4 :(得分:1)

与此处的大多数人一样,您可以使用memmove代替memcpy,因为它可以处理重叠范围。

然而,C ++解决方案将使用copy_backward,它明确地显示了您的要求,并将在屏幕后面为您选择最快的复制方法。这看起来像这样:

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

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