我听说c ++程序员应该避免使用memset,
class ArrInit { //! int a[1024] = { 0 }; int a[1024]; public: ArrInit() { memset(a, 0, 1024 * sizeof(int)); } };
所以考虑到上面的代码,如果你不使用memset,怎么能把[1..1024]填充为0?在C++中memset有什么问题?
谢谢.
在C++中std::fill
或者std::fill_n
可能是更好的选择,因为它是通用的,因此可以在对象和POD上操作.但是,memset
对原始字节序列进行操作,因此不应该用于初始化非POD.无论如何,如果类型是POD ,优化的实现std::fill
可以在内部使用特化来调用memset
.
问题不是在内置类型上使用memset(),而是在类(也称为非POD)类型上使用它们.这样做几乎总是会做错事并经常做致命的事情 - 例如,它可能会践踏虚函数表指针.
零初始化应如下所示:
class ArrInit { int a[1024]; public: ArrInit(): a() { } };
至于使用memset,有几种方法可以使用法更加健壮(就像所有这些函数一样):避免硬编码数组的大小和类型:
memset(a, 0, sizeof(a));
对于额外的编译时检查,还可以确保a
确实是一个数组(这样才有sizeof(a)
意义):
templatesize_t array_bytes(const T (&)[N]) //accepts only real arrays { return sizeof(T) * N; } ArrInit() { memset(a, 0, array_bytes(a)); }
但对于非字符类型,我想你用它填充的唯一值是0,零初始化应该已经以某种方式可用.
这有什么错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; }
使用visual c ++ 2008 32位进行编译并启用优化,将循环编译为 -
; Line 12 xor eax, eax mov ecx, 1024 ; 00000400H mov edi, edx rep stosd
这几乎就是memset可能会编译的内容.但是如果你使用memset,那么编译器就没有空间来执行进一步的优化,而通过编写你的意图,编译器可能会执行进一步的优化,例如注意到每个元素在被使用之前都被设置为其他元素,所以可以优化初始化,如果您使用了memset,它可能无法轻松完成.