【问题标题】:Are destructors of library types well defined?库类型的析构函数是否定义良好?
【发布时间】:2021-10-28 15:59:51
【问题描述】:

例如iterator 类型——这里我需要根据使用情况有一个不同类型的多态迭代器。所以我用用户定义的构造函数和析构函数创建了一个联合:

我特别质疑析构函数的名称(例如~iterator())。

#include <list>
#include <string>

struct val_origin {
    union {
        std::list<std::list<std::string>>::iterator iterenum;
        std::list<std::list<std::list<struct var>>>::iterator iterunorstr;
        std::list<struct var>::reverse_iterator vartypedef;
    };

    enum ORIG_ENUM {
        ORIG_ENUM_TYPE,
        ORIG_STRUC_TYPE,
        ORIG_TYPEDEF,
        ORIG_PLAIN
    } orig;

    val_origin(ORIG_ENUM orig) {
        switch (orig) if (0)
        case ORIG_ENUM_TYPE:
            new (&iterenum)decltype(iterenum) {};
        else if (0)
        case ORIG_STRUC_TYPE:
            new (&iterunorstr)decltype(iterunorstr) {};
        else if (0)
        case ORIG_TYPEDEF:
            new (&vartypedef)decltype(vartypedef) {};
    }

    val_origin& operator=(const val_origin& val_origin_in) {
        this->~val_origin();

        new (this)val_origin{ val_origin_in };
    }

    val_origin(const val_origin& val_origin) {
        switch (orig) if (0)
        case ORIG_ENUM_TYPE:
            iterenum = val_origin.iterenum;
        else if (0)
        case ORIG_STRUC_TYPE:
            iterunorstr = val_origin.iterunorstr;
        else if (0)
        case ORIG_TYPEDEF:
            vartypedef = val_origin.vartypedef;
    }

    ~val_origin() {
        switch (orig) if (0)
        case ORIG_ENUM_TYPE:
            iterenum.decltype(iterenum)::~iterator();
        else if (0)
        case ORIG_STRUC_TYPE:
            iterunorstr.decltype(iterunorstr)::~iterator();
        else if (0)
        case ORIG_TYPEDEF:
            vartypedef.decltype(vartypedef)::~reverse_iterator();
    }
};

现在我的问题是上面的代码在gcc 上编译得很好。但是当我切换到 clang 或 MSVC 时它会失败。

我的问题是这是否是标准代码(希望从标准中引用,我无法找到相关信息),如果不是,我实现此代码的其他选择是什么。

我正在尝试拥有一个动态(运行时)多态迭代器(相同的对象但不同类型的迭代器将被代码的不同部分适当地使用)。

代码在 MSVC 上失败,因为析构函数名称未知。

【问题讨论】:

  • 你应该使用std::variant而不是重新实现它。
  • 这个switch (orig) if (0) 构造的目的是什么?
  • @interjay 这是一个单语句切换。现在肯定正在调查std::variant - 谢谢。
  • 将其称为“单语句切换”并不能解释它的目的。这是很多没有明显目的的噪音。 switch 语句单个语句。
  • @pete 也许是隐式中断。不确定明确的 else 是否更好。

标签: c++ gcc visual-c++ polymorphism c++20


【解决方案1】:

析构函数的名称查找非常微妙,以支持诸如 typedef-names 之类的非类类型。但是,不能保证 iterator 在此处可用,因为迭代器不必是名为 iterator(或 reverse_iterator)的 class 类型,以便将其作为注入类提供 -名称,并且因为没有要查找的 unqualified 查找声明。

此外,在最近的澄清之后,规则是 decltype(…)::~… 无效([expr.prim.id.qual]/4)。当然,没有什么理由限定析构函数“名称”:你可以写

iterenum.~decltype(iterenum)();

等等。

【讨论】:

  • 非常令人印象深刻——这可能是 C++20 的一个新特性吗?无论如何,确切的 iterenum.~decltype(iterenum)(); 似乎正在 VC++2022 Preview 下编译。
  • @AnArrayOfFunctions:我认为自从decltype 在 C++11 中引入以来,这种情况并没有改变,尽管一些规范错误已定期修复。
  • 我这样说是因为它似乎没有用gcc 编译(它适用于clang 和msvc)。
  • @AnArrayOfFunctions:我认为这只是一个 GCC 错误;你可以尝试介绍using T=decltype(…);,然后写x.T::~T();
【解决方案2】:

您可能应该使用 C++ 机制(具有不同替代方案的派生类)而不是 --very-level-- C union。您必须查看生成的代码以检查运行时开销(如果有)。我怀疑这种不寻常的构造(类对象的union)可能会使一些编译器为(虚拟或其他)方法/字段访问生成不正确的代码。

【讨论】:

  • 您能指出代码中没有明确定义的特定内容吗?
  • @interjay,没有。但我会非常变化这样的代码。
猜你喜欢
  • 2021-11-02
  • 2011-10-04
  • 2011-10-04
  • 2013-11-02
  • 2014-08-26
  • 2018-01-27
  • 2012-03-09
  • 2012-01-23
相关资源
最近更新 更多