【问题标题】:Can you write a copy constructor for a union with const members?您可以为具有 const 成员的联合编写一个复制构造函数吗?
【发布时间】:2019-02-12 20:21:49
【问题描述】:

假设我有一个包含const 成员联合的结构,如下所示:

struct S
{
  // Members

  const enum { NUM, STR } type;

  union
  {
    const int a;
    const std::string s;
  };

  // Constructors

  S(int t_a) : type(NUM), a(t_a);

  S(const std::string & t_s) : type(STR), s(t_s);

};

到目前为止,一切都很好。但是现在说我想为这种类型编写一个复制构造函数。

这似乎不涉及做任何邪恶的事情,但由于我需要在成员初始化器中初始化 const 成员,我不知道如何根据依赖于 type 成员的逻辑来执行此操作。

问题:

  • 这个构造函数可以写吗?

  • 如果不是,这本质上是句法疏忽,还是语言不能支持这样的事情有什么根本原因?

【问题讨论】:

  • 可能想试试const std::variant<int, std::string>
  • 如果你想在联合中使用std::string,你真的需要使用标记联合。联合中的非平凡类型删除了所有联合特殊成员函数,并且正确地重新实现它们并非易事。
  • @NathanOliver:我确实标记了工会;这就是type 成员的用途。 (如果您只是指出我需要例如实现我自己的析构函数,我理解这一点,但为简洁起见,将其从代码示例中省略。)
  • 哦,我真傻。您正在建立一个标记工会。 std::variant 的源代码应该给你一个例子来说明如何做到这一点,因为它支持 const 成员。
  • 您应该可以在没有 UB 的复制构造函数主体中使用placement-new 来初始化as。相关:stackoverflow.com/questions/33058717/…

标签: c++ unions


【解决方案1】:

是的,可以在这里编写复制构造函数。实际上它已经在std::variant 实现中完成,它应该支持const-types 等。所以你的班级S 可以替换为

using S = std::variant<const int, const std::string>;

但是如果由于圆顶的原因你不能使用std::variant,那么可以使用std::construct_at函数来编写copy-constructor,如下所示:

#include <string>

struct S {
  const enum { NUM, STR } type;

  union {
    const int a;
    const std::string s;
  };

  S(int t_a) : type(NUM), a(t_a) {}
  S(const std::string & t_s) : type(STR), s(t_s) {}
  S(const S & rhs) : type(rhs.type) {
      if ( type == NUM ) std::construct_at( &a, rhs.a );
      if ( type == STR ) std::construct_at( &s, rhs.s );
  }
  ~S() {
      if ( type == STR ) s.~basic_string();
  }
};

int main() {
    S s(1);
    S u = s;

    S v("abc");
    S w = v;
}

演示:https://gcc.godbolt.org/z/TPe8onhWs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-26
    • 1970-01-01
    • 2015-08-10
    • 2012-08-15
    • 1970-01-01
    • 2017-02-10
    • 2018-09-06
    • 2013-08-07
    相关资源
    最近更新 更多