C++ 11移动类似联合类的构造函数

Dan*_*son 7 c++ unions move-constructor c++11

有没有更好的方法为类似联合的类构建移动构造函数?如果我在下面的代码中有类似类的类似类的类,有没有办法构建类或移动构造函数,它不需要像下面代码中的移动构造函数那样的switch语句.

class S {
    private:
        enum {CHAR, INT, DOUBLE} type; // tag
        // anonymous union
        union {
            char c;
            int n;
            double d;
        };

    public:
        // constructor if the union were to hold a character
        AS(const char c) {
            this->tag = AS::CHAR;
            this->c = c;
        }
        // constructor if the union were to hold a int
        AS(const int i) {
            this->tag = AS::INT;
            this->n = i;
        }
        // constructor if the union were to hold a double
        AS(const double d) {
            this->tag = AS::DOUBLE;
            this->d = d;
        }

        // Move constructor with switch statement
        S(S &&src) : type(std::move(src.type)) {
            switch(type) {
                case CHAR:
                    this->c = src.c);
                    src.c = 0;
                    break;
                case INT:
                    this->n = src.n;
                    src.n = 0;
                    break;
                case DOUBLE:
                    this->d = src.d;
                    src.d = 0
                    break;
                default:
                    break;
            }
        }
};
Run Code Online (Sandbox Code Playgroud)

Cub*_*bic 5

不,没有更好的方法。如果要安全地从包含任意类型的联合中移动,则必须从最后写入的联合的字段(如果有)中进行。另一个相反的答案是错误的,考虑一个例子

union SomethingLikeThisIsGoingToHappenInPractice {
  std::string what_we_actually_want_to_move;
  char what_we_do_not_care_about[sizeof(std::string)+1];
};
Run Code Online (Sandbox Code Playgroud)

如果在这里使用“最大”类型的移动构造函数,则必须在char此处选择数组,尽管移动实际上并没有做任何事情。如果std::string设置了该字段,您希望移动其内部缓冲区,如果您查看char数组,则不会发生这种情况。还要记住,移动语义是关于语义的,而不是关于移动内存的。如果这是您可以始终使用memmove并完成的问题,则不需要 C++11。

这甚至不涉及从您尚未编写为 C++ UB 的联合成员读取的问题,即使对于原始类型,尤其是对于类类型。

TL; DR 如果您发现自己处于这种情况,请使用 OP 最初提出的解决方案,而不是已接受的答案中的解决方案。


PS:当然,如果你只是移动一个只包含微不足道可移动的东西的联合,比如原始类型,你可以只使用默认的移动构造函数来复制内存;在这种情况下,除了为了一致性之外,首先拥有移动构造函数真的不值得。


CLL*_*CLL -1

由于联合作为一种数据类型,对于内部的所有字段引用内存中的同一位置(尽管该空间内较小字段(例如 4 字节的 char 数组 [4])的顺序取决于系统),因此可以只使用最大的字段移动并集。这将确保您每次都移动整个联合,无论您当前正在将联合用于哪些字段。

class S {
    private:
        enum {CHAR, INT, DOUBLE} type; // tag
        // anonymous union
        union {
            char c;
            int n;
            double d;
        };
    public:
        // Move constructor with switch statement
        S(S &&src) : type(std::move(src.type)) {
             this->d = src.d;
             src.d = 0;
        }
};
Run Code Online (Sandbox Code Playgroud)

  • 我不认为这实际上是标准的。GCC(可能还有 Clang)通过 C++ 中的联合支持类型双关,但 C++ 没有指定它。因此,如果您添加此详细信息,那么答案很好,但否则我认为它是不正确的。 (2认同)