C ++中琐碎类型的构造和初始化 [英] Construction and initialization of trivial types in C++

查看:83
本文介绍了C ++中琐碎类型的构造和初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

平凡的类可以简单地复制,并且具有普通的默认构造函数(a 平凡类型是其中之一或内置类的工作原理类似.

A trivial class is trivially copyable and has a trivial default constructor (a trivial type is either one of those or a built-in class that works similarly).

由于您可以使用memcpy 复制对象类型,并且默认初始化普通类型不会更改表示形式中的任何字节¹,下面的代码(使用C ++ 20概念)是否正确地初始化了传入对象的副本?

Since you can use memcpy to copy objects of trivial types, and since default-initializing trivial types doesn't change any of the bytes in the representation¹, does the following code (using C++20 concepts) correctly initialize a copy of the passed-in object?

#include <cstdlib>
#include <cstring>

#include <new>
#include <type_traits>

template <typename T>
T* copy_trivial(T orig) requires std::is_trivial_v<T>
{
    void* buf = std::aligned_alloc(alignof(T), sizeof(T));

    // Note the order of these statements
    std::memcpy(buf, &orig, sizeof(T));
    return new(buf) T;
}

(编译器资源管理器,提供了几个实例)

该代码似乎可以工作,因为将存在带有正确对象表示形式的已初始化对象.但是,如果在初始化后 没有任何反应,则该对象将具有

It seems like this code would work, because there would be an initialized object with the correct object representation. However, given that nothing happens after initialization, would the object instead have an indeterminate value²?

¹没有在单个位置中指定,但是用于默认初始化的链接过程将调用构造函数,该构造函数必须为默认初始化所有成员和基础;并且该递归在不执行初始化的情况下达到最低要求 -琐碎的类型.

¹ Not specified in a single location, but the linked procedure for default-initialization calls the constructor, which must be implicitly defined; the implicitly defined constructor default-initializes all the members and bases; and that recursion bottoms out at no initialization is performed for the built-in trivial types.

² [expr.new] p18.1 表示可以,但是注释不是规范性的,只有非放置new的情况才是合理的.

² The note in [expr.new]p18.1 says that it would, but notes are non-normative and it's plausible that this is only the case for non-placement new.

推荐答案

以下代码(使用C ++ 20概念)是否正确初始化传入对象的副本?

does the following code (using C++20 concepts) correctly initialize a copy of the passed-in object?

不,不是.

它确实返回了指向有效T的指针,但是在标准中没有任何内容要求该T的值是orig的值的副本.

It does return a pointer to a valid T, but there is nothing in the standard which requires the value of that T to be a copy of the value of orig.

琐碎类型的默认初始化被称为执行不初始化".但这与保留该内存的当前存储不同:[dcl.init]/12

Default initialization of trivial types is said to perform "no initialization". But this is not the same as preserving the current storage of that memory: [dcl.init]/12

获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,并且如果未对该对象执行初始化,则该对象将保留不确定的值,直到替换该值为止.

When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced.

请注意,它表示保留的是" 一个 不确定的值",而不是与该内存中相同的值".在没有显式保护的情况下,该标准不需要实现即可保留内存内容.

Note that it says that it retains "an indeterminate value", not "the same value that was in that memory". Without having that explicit protection, the standard does not require the implementation to preserve the memory's contents.

考虑调试版本.为了捕获错误,不执行初始化"的情况有时会用特定的字节填充未初始化的内存,以便您可以检测何时访问未初始化的内存.仅当不确定值"未将当前值保留在内存中时,这才对实现合法.

Consider debugging builds. To catch errors, cases where "no initialization is performed" will sometimes fill uninitialized memory with specific bytes, so that you can detect when you're accessing uninitialized memory. That is only legal for an implementation if "an indeterminate value" does not preserve the current values in the memory.

在C ++中,无法用另一个对象的按字节拷贝来初始化对象.您可以将memcpy放入任意内存中,但不能在该内存中显示一个对象,该对象从该内存中获取 的值.您可以将其存入一个现有对象,但是该对象将已经被初始化(除非在创建该对象时未执行任何初始化).

There is no way in C++ to initialize an object with a byte-wise copy of another object. You can do memcpy's into arbitrary memory, but you cannot manifest an object in that memory which takes its value from that memory. And you can memcpy into an existing object, but that object will already have been initialized (unless no initialization was performed when it was being created).

因此,您所能做的最好是颠倒这两个语句的顺序.

So the best you can do is reverse the order of the two statements.

这篇关于C ++中琐碎类型的构造和初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆