gpt4 book ai didi

c++ - 可选未初始化的类:std::is_trivially_constructible 对于非默认构造函数似乎不正确?

转载 作者:行者123 更新时间:2023-12-04 07:54:15 25 4
gpt4 key购买 nike

我觉得std::is_trivially_constructible<T, Arg>没有告诉我真相。一、语境:
我有一个小 vector 类,VectorND<T, N> .默认构造它默认构造它的成员,所以 VectorND<float, 2>{} == VectorND<float, 2>{float{}, float{}} == VectorND<float, 2>{0.f, 0.f} .这是所需的行为。
然而,有时,对于性能关键代码,我想构造它们未初始化。我的想法是我可以使用这样的标签类型:

struct uninitalized_t {};
static constexpr uninitalized_t uninitalized;
...
VectorND(uninitalized_t) {}
...
VectorND<float, 2> x{uninitalized}; //< Tell x to be uninitialized.
我可以让它工作。首先,如果我这样做
template <typename T, std::size_t N>
class VectorND {
std::array<T, 2> x;
public:
VectorND() = default;
T& operator[](std::size_t i) { return x[i]; }
};
https://godbolt.org/z/oTvo33xEb
然后默认构造函数使数据未初始化。如果是 VectorND() {} 也是一样.
如果我成功了 VectorND() : x{} {}然后将数据归零,使其不再像预期的那样简单地构建。这是所需的默认行为。
但是如果我添加 explicit VectorND(uninitalized_t) {} ,然后 VectorND<float, 2> x{uninitialized}似乎未初始化: https://godbolt.org/z/j9KWhPT7n这又是我想要的。但不知为何, std::is_trivially_constructible_v<VectorND<float, 2>, uninitalized_t>false .为什么?我试过了
VectorND() = default; // Or VectorND() {};
explicit VectorND(uninitalized_t) {}
VectorND() = default; // Or VectorND() {};
explicit VectorND(uninitalized_t) : VectorND() {}
我仍然得到 std::is_trivially_constructible_v<VectorND<float, 2>, uninitalized_t> == false . https://godbolt.org/z/3n1Mz9dWd
为什么?

最佳答案

简答
这不起作用,因为这不是标准定义的普通构造函数。
Trivial 与初始化(或缺少初始化)无关,它只是标准列出的一组要求,用于将构造函数定义为平凡的——一种使编译器能够生成更好的代码并由库作者进行优化的状态。
长答案
微不足道的状态,就C++标准而言,与成员是否被初始化无关。平凡的一个副产品是,您可能会从经历平凡值初始化的对象中获得未初始化的数据——但这并不意味着未初始化的数据就是平凡的定义。
正式地说,该标准只是概述了非常具体的构造函数被认为是微不足道的标准:

  • 默认构造函数由 class.default.ctor/3 定义

    A default constructor is trivial if it is not user-provided and if:

    • its class has no virtual functions ([class.virtual]) and no virtual base classes ([class.mi]), and
    • no non-static data member of its class has a default member initializer ([class.mem]), and
    • all the direct base classes of its class have trivial default constructors, and
    • for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.

    Otherwise, the default constructor is non-trivial.


  • 复制/移动构造函数由 class.copy.ctor/11 定义

    A copy/move constructor for class X is trivial if it is not user-provided and if:

    • class X has no virtual functions ([class.virtual]) and no virtual base classes ([class.mi]), and
    • the constructor selected to copy/move each direct base class subobject is trivial, and
    • for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;

    otherwise the copy/move constructor is non-trivial.



  • 注: operator=也有类似的要求对于析构函数
    但是,对于不是简单的复制、移动或默认构造函数的自定义构造函数,没有任何实际定义。这意味着任何自定义构造函数 不能 被认为是微不足道的。
    这也有效地意味着 std::is_trivially_constructible<T,Args...>::value只能评估为 true如果它测试默认构造函数、复制构造函数或移动构造函数。
    为什么微不足道很重要?
    “平凡”状态的存在是因为它为编译器和库作者提供了更好的优化保证。用于复制/移动的简单构造函数很简单 mov只复制数据的指令(而不是需要任何清理或重新布线)
    对象的构造函数通常可能需要)。
    此外,如果一个类型满足足够简单的要求,它可能是“可简单复制的”——这允许编译器和库作者简单地用 std::memcpy 复制数据。而不是要求构造函数调用。这也可用于在不违反严格别名的情况下查看不同的对象表示。

    关于c++ - 可选未初始化的类:std::is_trivially_constructible 对于非默认构造函数似乎不正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66786672/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com