YSC*_*YSC 20 c++ metaprogramming sfinae c++14 c++20
假设我已经定义了一个zero_initialize()函数:
template<class T>
T zero_initialize()
{
T result;
std::memset(&result, 0, sizeof(result));
return result;
}
// usage: auto data = zero_initialize<Data>();
Run Code Online (Sandbox Code Playgroud)
调用zero_initialize()某些类型会导致不确定的行为1,2.我目前正在执行T验证std::is_pod.由于这个特性在C++ 20中被弃用以及概念的出现,我很好奇zero_initialize()应该如何发展.
std::uninitialized_fill而不是std::memset吗?为什么?1) 删除班级的所有成员.
2) 在库类(std :: string)上使用memset时,"未定义的行为"是什么原因?[关闭]
Nic*_*las 23
在C++中技术上没有对象属性,它指定用户代码在法律上可以memset是C++对象.这包括POD,所以如果你想成为技术人员,你的代码永远不会正确.甚至TriviallyCopyable也是关于在现有对象之间进行逐字节复制的属性(有时通过中间字节缓冲区); 它没有说明发明数据并将其推入对象的位.
话虽这么说,你可以合理地肯定,如果你测试is_trivially_copyable 和 这将是有效的is_trivially_default_constructible.最后一个很重要,因为一些TriviallyCopyable类型仍然希望能够控制它们的内容.例如,这样的类型可以有一个int始终为5 的私有变量,在其默认构造函数中初始化.只要没有访问变量的代码改变它,它就会一直是5.C++对象模型保证了这一点.
所以你不能memset这样的对象,仍然可以从对象模型中获得明确定义的行为.
什么(最小)特征/概念可以保证memsetting一个对象是明确定义的?
根据std::memsetcppreference的引用,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;
}
Run Code Online (Sandbox Code Playgroud)
这里我们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 {};
}
Run Code Online (Sandbox Code Playgroud)