Реализация конструктора перемещения тегового объединения - PullRequest
0 голосов
/ 01 мая 2018

Я реализовал теговое объединение, используя класс, содержащий анонимное объединение и тег:

class LogFile
{
  public:
    LogFile(std::ostream& stdStream);
    LogFile(std::ofstream fileStream);
    LogFile(LogFile&& logFile);
    ~LogFile();

    std::ostream& getStream();

  private:
    enum { STD_STREAM, FILE_STREAM } streamType_;
    union
    {
        std::ostream *stdStream_;
        std::ofstream fileStream_;
    };
};

У меня проблемы с реализацией конструктора перемещения. В перегруженных «обычных» конструкторах я знаю, какой элемент объединения инициализировать:

LogFile::LogFile(std::ofstream fileStream)
: streamType_(FILE_STREAM), fileStream_(std::move(fileStream))
{
}

Но в конструкторе перемещения как узнать, какой из stdStream_ или fileStream_ мне нужно инициализировать. Я не могу проверить значение streamType_ в списке инициализатора.

1 Ответ

0 голосов
/ 01 мая 2018

Если вы не делаете это на практике, замените ваш помеченный союз на std::variant. Это намного более безопасно.


Вместо того, чтобы вызывать конструктор в списке инициализатора члена, вы можете условно вызвать его позже с помощью Placement-New.

Обычно, если вы не указываете конструктор в списке инициализатора члена, вызывается конструктор по умолчанию. Но для членов union {...}; конструктор вообще не вызывается.

LogFile(LogFile&& other) : streamType_(other.streamType_)
{
    switch (streamType_)
    {
      case FILE_STREAM:
        new (&fileStream_) std::ofstream(std::move(other.fileStream_)); // <--
        break;
      case STD_STREAM:
        stdStream_ = other.stdStream_;
        other.stdStream_ = 0;
        break;
    }
}

Обратите внимание, что вы должны вручную вызывать деструктор в ~LogFile(), и вам также необходимо пользовательское назначение перемещения. Вот почему std::variant лучше.

...