假设我已经定义了一个zero_initialize()
函数:
template<class T>
T zero_initialize()
{
T result;
std::memset(&result, 0, sizeof(result));
return result;
}
// usage: auto data = zero_initialize<Data>();
为某些类型调用zero_initialize()
会导致未定义的行为 1 2 。我目前正在强制T
验证std::is_pod
。随着C ++ 20中不赞成使用此特性以及概念的出现,我很好奇zero_initialize()
应该如何发展。
std::uninitialized_fill
而不是std::memset
吗?为什么? 1) Erase all members of a class。
2) What would be reason for “undefined behaviors” upon using memset on library class(std::string)? [closed]
答案 0 :(得分:23)
从技术上讲,C ++中没有对象属性,该属性指定用户代码可以合法地memset
C ++对象。其中包括POD,因此,如果您想成为技术专家,则代码永远是不正确的。甚至TriviallyCopyable都是关于在现有的对象之间进行字节复制的属性(有时通过中间字节缓冲区);它没有说明发明数据并将其推入对象的位。
话虽如此,如果您测试is_trivially_copyable
和 is_trivially_default_constructible
,您可以合理地确定这将起作用。最后一个很重要,因为某些TriviallyCopyable类型仍然希望能够控制其内容。例如,这种类型可以有一个私有int
变量,该变量始终为5,并在其默认构造函数中初始化。只要没有可访问该变量的代码对其进行更改,它将始终为5。C++对象模型对此进行了保证。
因此,您无法memset
这样的对象,仍然无法从对象模型中获得明确定义的行为。
答案 1 :(得分:8)
什么(最小)特征/概念可以保证对对象的精确定义?
对于std::memset
reference on cppreference,memset
在非 TriviallyCopyable 类型上的行为是不确定的。因此,如果可以memset
一个 TriviallyCopyable ,则可以向您的班级添加一个static_assert
来进行类似的检查
template<class T>
T zero_initialize()
{
static_assert(std::is_trivial_v<T>, "Error: T must be TriviallyCopyable");
T result;
std::memset(&result, 0, sizeof(result));
return result;
}
在这里,我们使用std::is_trivial_v
来确保该类不仅是可微复制的,而且还具有一个微不足道的默认构造函数,因此我们知道将其初始化为零是安全的。
我应该使用
std::uninitialized_fill
而不是std::memset
吗?为什么呢?
您不需要在这里,因为您只在初始化单个对象。
此函数是否由于一种C ++初始化语法中的一部分类型而过时?还是将来的C ++版本即将出现?
值或括号初始化确实会使此功能“过时”。 T()
和T{}
将为您提供初始化的值T
,如果T
没有默认的构造函数,它将被初始化为零。这意味着您可以将函数重写为
template<class T>
T zero_initialize()
{
static_assert(std::is_trivial_v<T>, "Error: T must be TriviallyCopyable");
return {};
}
答案 2 :(得分:0)
保证您的zero_initialize
实际上将对象初始化为零的最一般的可定义特征是
template <typename T>
struct can_zero_initialize :
std::bool_constant<std::is_integral_v<
std::remove_cv_t<std::remove_all_extents_t<T>>>> {};
不太有用。但是标准中关于基本类型的按位或字节表示的唯一保证是[basic.fundamental] / 7“整数类型的表示应通过使用纯二进制计算系统来定义值”。不能保证所有字节均为零的浮点值是零值。不能保证所有字节为零的任何指针或指针到成员的值都是空指针值。 (尽管实际上这两种情况通常都是正确的。)
如果一个平凡可复制的类类型的所有非静态成员都是(cv限定)整数类型的(数组),我认为也可以,但是除非有反射,否则无法进行测试到C ++。