C++ 中纹理数据指针的联合

Union of texture data pointers in C++

我从不同来源捕获纹理数据,其中数据在 BYTE* 或 ID3D11Texture2D COM 指针中,因此我尝试制作一个包含以下联合类型集合的 STL 容器。

    _COM_SMARTPTR_TYPEDEF(ID3D11Texture2D, __uuidof(ID3D11Texture2D));

    union TextureData
    {
        ID3D11Texture2DPtr m_tex2D;
        BYTE* m_byte;
    };

但是当我只编译上面的声明而不使用 STL 容器的联合类型时,我看到以下警告:

warning C4624: '....::TextureData': destructor was implicitly defined as deleted

谁能告诉我在宣布这个联盟时我应该注意什么?

编辑:

我本来打算这样用的,但是在使用之前出现了编译警告:

std::array< std::tuple<< DXGI_FORMAT, TextureData>>, 4>;

编辑 2:

我发现如果我像下面这样使用,警告不会显示:

    union TextureData
    {
        ID3D11Texture2D* m_tex2D;
        BYTE* m_byte;
    };

来自union documentation

If a union contains a non-static data member with a non-trivial special member function (copy/move constructor, copy/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer.

如果您还记得 C++ 不跟踪联合 的活动成员,那么这条规则就很有意义,因此当联合被析构时,它不知道析构函数呼叫哪个成员。当然,如果所有成员都有平凡的析构函数,这没有关系。

来自_COM_SMARTPTR_TYPEDEF documentation

A smart pointer is usually referenced by the typedef definition provided by the _COM_SMARTPTR_TYPEDEF macro. This macro takes an interface name and the IID and declares a specialization of _com_ptr_t with the name of the interface plus a suffix of Ptr.

来自 _com_ptr_t 的来源:

    // If we still have an interface then Release() it. The interface
    // may be NULL if Detach() has previously been called, or if it was
    // never set.
    //
    ~_com_ptr_t() throw()
    {
        _Release();
    }

如您所见,_com_ptr_t 有一个非平凡的析构函数,因此您需要向联合体添加一个显式析构函数。这是您需要手动调用对象的析构函数的罕见情况之一。像这样:

    union TextureData
    {
        ID3D11Texture2DPtr m_tex2D;
        BYTE* m_byte;

        ~TextureData() {
            if (/* m_tex2D is the active member */)
                m_tex2D.~_com_ptr_t();
        }
    };

请注意,由于TextureData不跟踪其活跃成员,因此您需要自行确定m_text2D是否活跃。

您可以使用的另一种方法是使用 std::variant 而不是原始联合。与联合相反,变体 确实 跟踪活动成员("alternative")并为您调用适当的析构函数。