Изменяет ли конструктор перемещения память, на которую указывает «это»?

У меня есть некоторые недоразумения по поводу конструктора перемещения С++. Если компилятор неявно синтезирует конструктор перемещения, что будет делать этот конструктор перемещения? Будет ли просто "this" указывать на объект, который используется для инициализации? есть пример:

struct Foo {
    int i;
    int *ptr;
};

Foo x;
Foo y(std::move(x));

будет ли неявно синтезированный конструктор перемещения просто заставлять this в y указывать на память, в которой находится x? Если да, то как обеспечить, чтобы x можно было разрушить после перемещения (если x уничтожается, будут ли члены в y действительными)? если нет, то как работает конструктор перемещения y?

1. Нет, и 2. как работают операторы перемещения (по сравнению с тем, как работают копировщики), подробно рассматривается во множестве вопросов на этом сайте. этот например. И особенно этот.

WhozCraig 10.04.2022 10:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

will the implicitly synthesized move constructor just make this in y point to the memory that x is in?

синтезатор движения будет членское перемещение членами данных своих аргументов (x здесь) для создаваемого объекта (y здесь).

Также обратите внимание, что для встроенных типов, таких как int, перемещение аналогично копированию.


how to ensure that x is destructible after the move

Поскольку перемещение — это то же самое, что и копирование для встроенных типов, x и y не зависят друг от друга. Поэтому, когда x будет уничтожен, y не пострадает.


will the synthesized move constructor set the ptr of x to nullptr?

Нет, движок синтеза не сделает этого за вас. Он просто будет перемещать элементы данных по элементам. Для встроенных типов это означает то же самое, что и копирование.


if it does not do this, then the ptr of x will still point to the memory to which the ptr of y points, then you cannot safely destroy x.

В этом случае вам нужно будет написать определяемый пользователем движущийся элемент, который явно устанавливает ptr из x в nullptr, чтобы при уничтожении x не затрагивалось y.

как конструктор перемещения перемещает элементы типа int или string? Будет ли он просто копировать значения этих членов в инициализированный объект класса?

kaiyu wei 10.04.2022 10:39

И установит ли синтезированный конструктор перемещения ptr из x значение nullptr? если он этого не сделает, то ptr из x все равно будет указывать на память, на которую указывает ptr из y, тогда вы не сможете безопасно уничтожить x.

kaiyu wei 10.04.2022 10:47

@kaiyuwei Для встроенных типов, таких как int, move это то же самое, что копирование. Больше можно найти здесь: Имеют ли встроенные типы семантику перемещения?. То есть для встроенных типов move является копией.

Anoop Rana 10.04.2022 10:57

@kaiyuwei Нет, синтезатор движения не установит ptr из x на nullptr. Он просто перемещает элементы данных из x в y, не делая ничего другого. Также обратите внимание, что для элементов данных встроенного типа, таких как int, перемещение аналогично копированию. Итак, x и y не зависят друг от друга. Если оба указателя x и y указывают на одну и ту же память, вам нужно будет написать собственный конструктор перемещения, который установит x в nullptr. Синтезированный ctor не сделает этого за вас.

Anoop Rana 10.04.2022 11:08

@kaiyuwei Вам придется написать определяемый пользователем механизм перемещения, который явно устанавливает ptr из x на nullptr, чтобы при уничтожении xy не затрагивалось.

Anoop Rana 10.04.2022 11:15

will the implicitly synthesized move constructor just make this in y point to the memory that x is in?

Как заметил Anoop, он будет вызывать конструктор перемещения для каждого члена источника, который нужно переместить (x), на элементы назначения (y или this, если вы представляете себя «внутри» этого синтезированного конструктора перемещения).

Итак, в вашем примере:

  • intx.i будет перемещен на y.i (this->i)
  • int*x.ptr будет перемещен на y.ptr (this->ptr).

Обратите внимание, что эти конкретные перемещения будут выполняться путем копирования.

how to ensure that x is destructible after the move (if x is destroyed, will members in y be valid)?

Это всегда разрушаемо. Что касается того, является ли он «действительным», это зависит от того. Конструкция перемещения по умолчанию фактически была копией. Теперь два объекта указывают на то, на что указывает x.ptr. Если этот int был ресурсом, «принадлежавшим» x (возможно, ресурс был строкой целых чисел в конце 0 в куче), то вы только что «поделились» этим ресурсом.

Если вы не хотите «делиться» им, вы могли бы явно написать конструктор перемещения для Foo, который сбрасывает указатель «перемещенного из» объекта или каким-то образом помечает его как недействительный.

struct Foo {
  ...
  Foo(Foo&& other) {
    this->i = other.i;
    this->ptr = other.ptr;
    other.ptr = nullptr;
  }
}

В общем, лучше вообще не полагаться на "перемещенные" объекты, т.е. позаботиться о том, чтобы они были уничтожены как можно скорее.

Спасибо, Жоао, поскольку x.ptr и y.ptr указывают на один и тот же объект, как вы можете говорить, что x разрушаем? поскольку, если вы уничтожите x, то объект, на который указывает y.ptr, также будет уничтожен, что сделает ```y.ptr''' недействительным.

kaiyu wei 10.04.2022 11:12

Правильно, но в примере, который вы впервые опубликовали, такого деструктора члена ptr не было! Таким образом, то, на что указывает ptr, будет уничтожено нет. Если есть мы такой деструктор, то этот деструктор, вероятно, должен проверять, является ли ptrnullptr, а не уничтожать его. И это хорошая причина определить конструктор перемещения, как я предложил.

Joao Tavora 10.04.2022 11:28

Теперь мне достаточно ясно. Большое спасибо!

kaiyu wei 10.04.2022 11:43

Другие вопросы по теме