Может ли `* this` быть` move () `d?

Я хотел бы определить класс для сортировки данных; когда сортировка закончена, я хотел быmove маршаллированные данные изнутри, что, вероятно, сделает недействительным маршаллирующий объект.

Я считаю, что это возможно сstatic функцияextractData ниже:

class Marshaller
{
  public:
    static DataType extractData(Marshaller&& marshaller)
    {
      return std::move(marshaller.data);
    }
  private:
    DataType data;
}

Это немного неудобно для вызова, хотя:

Marshaller marshaller;
// ... do some marshalling...
DataType marshalled_data{Marshaller::extractData(std::move(marshaller))};

Так можно ли обернуть его функцией-членом?

DataType Marshaller::toDataType()
{
  return Marshaller::extractData(std::move(*this));
}

Это, конечно, можно назвать с помощью:

DataType marshalled_data{marshaller.toDataType()};

... что, на мой взгляд, выглядит намного лучше. Но этоstd::move(*this) вещь выглядит ужасно подозрительно. В контексте звонкаtoDataType(), marshaller не может быть использован снова, но я не думаю, что компилятор может знать, что: тело функции может быть вне модуля компиляции вызывающей стороны, так что нет ничего, что указывало бы на то, чтоmarshaller имелmove() применяется к нему.

Это неопределенное поведение? Это прекрасно? Или где-то посередине? Есть ли лучший способ для достижения той же цели, желательно без использования макроса или требующий от вызывающего явноmove marshaller?

РЕДАКТИРОВАТЬ: И с G ++, и с Clang ++ я обнаружил, что я не только могу скомпилировать приведенный выше вариант использования, но и на самом деле могупродолжать вносить изменения в основные данные через маршаллерзатем повторно извлеките измененные данные, используяtoDataType функция. Я также обнаружил, чтоуже извлечены данные вmarshalled_data продолжал менятьсяmarshallerчто указывает на то, чтоmarshalled_data распределяется междуmarshaller и вызывающий контекст, поэтому я подозреваю, что здесь есть утечка памяти или неопределенное поведение (из-за двойного удаления).

РЕДАКТИРОВАТЬ 2: Если я положу заявление для печати вDataTypeдеструктор, оказываетсядважды когда звонящий покидает сферу. Если я включу член данных вDataType который имеет массив в нем, с соответствующимnew[] а такжеdelete[]Я получаюglibc Ошибка "двойного освобождения или коррупции". Так что я не уверен, как этомог быть в безопасности, хотя в нескольких ответах говорилось, что это технически разрешено. Полный ответ должен объяснить, что требуется для правильного использования этой техники с нетривиальнымDataType учебный класс.

РЕДАКТИРОВАТЬ 3: Этого достаточно кроличьей норе / червячной ямы, которую я открылДругой вопрос чтобы решить мои оставшиеся проблемы.

Ответы на вопрос(5)

Ваш ответ на вопрос