Jic*_*hao 36 c++ initialization memset
我听说c ++程序员应该避免使用memset,
class ArrInit {
//! int a[1024] = { 0 };
int a[1024];
public:
ArrInit() { memset(a, 0, 1024 * sizeof(int)); }
};
Run Code Online (Sandbox Code Playgroud)
所以考虑到上面的代码,如果你不使用memset,怎么能把[1..1024]填充为0?在C++中memset有什么问题?
谢谢.
Cha*_*via 49
在C++中std::fill或者std::fill_n可能是更好的选择,因为它是通用的,因此可以在对象和POD上操作.但是,memset对原始字节序列进行操作,因此不应该用于初始化非POD.无论如何,如果类型是POD ,优化的实现std::fill可以在内部使用特化来调用memset.
小智 44
问题不是在内置类型上使用memset(),而是在类(也称为非POD)类型上使用它们.这样做几乎总是会做错事并经常做致命的事情 - 例如,它可能会践踏虚函数表指针.
Unc*_*ens 23
零初始化应如下所示:
class ArrInit {
int a[1024];
public:
ArrInit(): a() { }
};
Run Code Online (Sandbox Code Playgroud)
至于使用memset,有几种方法可以使用法更加健壮(就像所有这些函数一样):避免硬编码数组的大小和类型:
memset(a, 0, sizeof(a));
Run Code Online (Sandbox Code Playgroud)
对于额外的编译时检查,还可以确保a确实是一个数组(这样才有sizeof(a)意义):
template <class T, size_t N>
size_t array_bytes(const T (&)[N]) //accepts only real arrays
{
return sizeof(T) * N;
}
ArrInit() { memset(a, 0, array_bytes(a)); }
Run Code Online (Sandbox Code Playgroud)
但对于非字符类型,我想你用它填充的唯一值是0,零初始化应该已经以某种方式可用.
AnT*_*AnT 10
这有什么错memset在C++中的大部分是错的同样的事情memset在C. memset填补物理零位模式存储区域,而在病例几乎100%的现实需要,以填补相应类型的逻辑零值的数组.在C语言中,memset只保证为整数类型正确初始化内存(并且它对所有整数类型的有效性,而不仅仅是char类型,是C语言规范中添加的相对较新的保证).不能保证将任何浮点值正确设置为零,不能保证产生正确的空指针.
当然,上述内容可能被视为过于迂腐,因为在给定平台上活跃的附加标准和约定可能(并且肯定会)扩展其适用性memset,但我仍然建议遵循Occam的剃刀原则:不要依赖任何其他标准和惯例,除非你真的必须这样做.C++语言(以及C语言)提供了几种语言级功能,使您可以使用正确类型的正确零值安全地初始化聚合对象.其他答案已经提到了这些功能.
它"糟糕",因为你没有实现你的意图.
您的目的是将数组中的每个值设置为零,并且您编写的内容是将原始内存区域设置为零.是的,这两件事具有相同的效果,但是简单地将代码编写为零以使每个元素更清晰.
而且,它可能没有效率.
class ArrInit
{
public:
ArrInit();
private:
int a[1024];
};
ArrInit::ArrInit()
{
for(int i = 0; i < 1024; ++i) {
a[i] = 0;
}
}
int main()
{
ArrInit a;
}
Run Code Online (Sandbox Code Playgroud)
使用visual c ++ 2008 32位进行编译并启用优化,将循环编译为 -
; Line 12
xor eax, eax
mov ecx, 1024 ; 00000400H
mov edi, edx
rep stosd
Run Code Online (Sandbox Code Playgroud)
这几乎就是memset可能会编译的内容.但是如果你使用memset,那么编译器就没有空间来执行进一步的优化,而通过编写你的意图,编译器可能会执行进一步的优化,例如注意到每个元素在被使用之前都被设置为其他元素,所以可以优化初始化,如果您使用了memset,它可能无法轻松完成.