Может ли `* 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: Этого достаточно кроличьей норе / червячной ямы, которую я открылДругой вопрос чтобы решить мои оставшиеся проблемы.