使用new运算符的memset和memcpy

4

我能否可靠地使用C++中的memset和memcpy操作符,以及用new分配的内存?

编辑:

是的,可以用来分配本地数据类型。

例如:

BYTE *buffer = 0;
DWORD bufferSize = _fat.GetSectorSize();
buffer = new BYTE[bufferSize];

_fat.ReadSector(streamChain[0], buffer, bufferSize);

ULONG header = 0;
memcpy(&header, buffer, sizeof(ULONG));
5个回答

7
只要您只使用“new”来分配内置类型和/或POD类型,是可以的。但是,对于类似以下内容的情况:
std::string * s = new string;
memset( s, 0, sizeof(*s) );

如果你使用错误,那么将会导致灾难。

不过我必须问一下,为什么你和其他人似乎如此着迷于这些函数——我不认为我在自己的代码中曾经使用过它们。对于memcpy()来说,使用具有自己复制和赋值功能的std::vector似乎是更好的选择,而我从来没有真正相信把所有东西都设置为零的魔法,这似乎是memset()的主要用途。


1
@Elii - 首先,我为什么要这样做?其次,std::vector <int> v(0,SIZE)。 - anon
如果你正在使用原始数据,也就是我的情况,从某种类型的IO(文件、网络等)读取数据怎么办?有没有一种有效的方法可以不依赖于字节缓冲区和mem...()函数来完成呢?抱歉,我知道这应该是一个新问题,但我们已经在这里了 :) - Andres
2
@Andres 像我说的那样,使用 std::vector <char> - 它可以做到手动分配数组所能做到的一切,并且更加安全和方便。你还应该看一下 STL 算法,比如 std::copy。 - anon
正如Neil所说,通常来说,memset类的功能并不是你想要的。但是如果你需要,那么请使用std::fill。它与POD类型以及非POD类型一样有效。 - jalf
2
@TommyA:对于POD结构体,普通值初始化会将其清零。无需在初始化之后调用单独的函数。 - jalf
显示剩余6条评论

2

确实可以。

这是一个经典的memset实现(来自Android libc):

void*  memset(void*  dst, int c, size_t n)
{
    char*  q   = dst;
    char*  end = q + n;

    for (;;) {
        if (q < end) break; *q++ = (char) c;
        if (q < end) break; *q++ = (char) c;
        if (q < end) break; *q++ = (char) c;
        if (q < end) break; *q++ = (char) c;
    }

  return dst;
}

很明显,dst指针可以通过任何有效的方式进行分配(newmalloc,甚至静态分配)- memset并不关心。

很酷,但是这里的代码假设int始终为4个字节。 - Andres
4次重复被称为“循环展开”。它可以增加非常简单的重复语句的循环效率。 - Eli Bendersky
1
memset 不关心,但你要覆盖的对象肯定会关心。在非 POD 类型上执行此操作是不安全的。 - jalf
请问您能否解释一下在这个上下文中您使用“规范”的含义? - Rob Kennedy
@Rob:取自真实的C库实现 - Eli Bendersky

2

当然可以,虽然使用new分配的内存来自“自由存储区”,但它仍然只是应用程序内存地址空间中的一部分。memset和memcpy只需要源地址和目标地址参数,这些参数可以是应用程序地址空间中的任何地址。

实际上,一些标准库算法本身简化为一个简单的memcpy(通过迭代器复制向量源和目标)。


1

你提到了使用memset,但是你的代码没有调用它。

你可以利用语言的特性一次性分配和初始化内存:

int someInts [256] = {0};

这将分配一个256个int的数组,并将每个元素设置为零,实现与以下代码相同的功能:
int someInts[256];
memset(someInts, 0, sizeof(someInts));

...但是,根据您的编译器如何优化alloc-memset代码块,可能会更快。


需要注意的是,零是不必要的,int someInts [256] = {}; 就可以了。 - avakar
@avakar:确实。我的倾向是在写自我说明的代码时包含零。 - John Dibling
就我个人而言,我觉得“{0}”很令人困惑——为什么要明确指定数组的第一个元素的值呢?当然,你的看法可能会有所不同。 - avakar
1
好吧,我这样做并不是为了更好地理解自己的代码 - 我已经知道 {} 的含义。实际上,我这样做是为了让那些不熟悉这种特定语法的程序员至少能够猜测到这里发生了什么,以便他们可以在他们选择的文本中查找它。很多其他技能和经验丰富的 C++ 程序员都不理解这个语法。我甚至在阅读了标准的封面之前都不理解它(例如,知道它是允许的),那么有多少 C++ 程序员会这样做呢? - John Dibling
1
对于不熟悉初始化语义的程序员,最好使用 {} 使他们感到困惑,而不是使用 {0} 来制造理解的错觉。我见过试图使用 {n} 来“n-初始化”数组的尝试不止一次。 - avakar

1

取决于你所分配的内容。如果你已经分配了POD(Plain Old Data),即类似于

char* p = new char[100];
的数据,则与malloc没有任何区别。但是,如果你已经分配了一个或多个对象,则使用memcpy或memset可能会导致未定义的行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接