После вызова перемещающего конструктора для базового класса мы не знаем, какие значения лежат в other в полях базового класса. А поля производного не изменились. static_cast / dynamic_cast к производному классу в конструкторе? Это дичь какая-то. Конечно умышленно навредить можно. Но в реальном коде такого не может быть. Вызов виртуального метода у other? Ну тут может быть даже можно какой-нибудь искусственный пример придумать. Но в этом конкретном случае виртуальных методов нет. То есть в каких-то малореальных искусственных ситуациях при вызове Derived(Derived&& other) : Base(std::move(other)) конструктор базового класса может изменить поля в Derived, но сам по себе вызов move ничего не портит. Это эквивалентно Derived(Derived&& other) : Base((Base&&)other).
Да, в случайном. И нет, не важно стало что в базовом классе - пока в конструкторе Derived не берутся данные из базового класса. Не move меняет состояние объекта, а конструктор. "в неспецифицированном состоянии" - это только о том, что стандарт не оговаривает, какое значение будет. И компилятору не нужно ничего различать. До того, как в с++ завезли rvalue ссылки, был такой auto_ptr и у него обычный оператор присваивания менял значение аргумента: после a = b; значение b занулялось - он использовал обычную lvalue ссылку. И это разрыв шаблона для программиста. А компилятору всё равно. Так вот если вы в конструкторе поменяете &&other на &other и уберете std::move, то с точки зрения компилятора код надо генерировать точно такой же. А у программиста будет некоторое недоумение по поводу неожиданного изменения параметра.
Объект никуда не перемещен. И компилятор ничего, кроме передачи объекта в функцию, с ним не делает. Как и любое другое приведение типа ничего само не делает с исходным объектом. Функция может делать с объектом что угодно, но оставить его в валидном состоянии. Например, после a = std::move(b); в b может оказаться значение, бывшее до присваивания в a - если поменять значения местами дешевле, чем создать пустое значение. Но функция тут - конструктор базового класса. Она получает ссылку на базовый класс, и не может ничего сделать с полями производного класса.
Откуда взялось "компилятор помечает объект перемещенным"? Объект помечается как rvalue, что позволяет передать его в функцию, принимающую rvalue ссылку. И ничего больше.
Тут вообще-то вся статья рассказывает, что move ничего не перемещает. А конструктор по ссылке базового класса может изменить только что-то в базовом классе.
Если в конструкторе Derived (или derived_data_) пытаться обращаться к элементам базового класса, то проблема с тем, что базовый объект перемещен, конечно будет. А если не обращаться, то вроде нормально.
Это не я придумал. Этот вариант есть в той статье в википедии, которая упоминается в начале. "Из всех семей с двумя детьми один ребёнок выбирается случайным образом, и пол этого ребёнка сообщается (т.е. говорится либо «хотя бы один ребёнок — мальчик», либо «хотя бы один ребёнок — девочка»). В этом случае ответ 1/2"
Ну это вы считаете, что "известно, что пол одного из детей - девочка" - математически строгое утверждение. А на бытовом уровне это вполне может значить "видели гуляющим с дочерью", то есть как раз что пол случайного ребёнка - девочка. То есть пока вы не объясните, откуда известно про пол одного из детей, вопрос может быть неоднозначным.
Нет разницы. Не в том проблема. Как мы узнали, что на одной из монет орел? Пока вы этого не объясните, утверждение "известно, что на одной из монет орел" может читаться как "мы посмотрели на одну из монет, а на вторую не смотрели".
Откуда возникает парадокс - люди понимают фразу "семья с двумя детьми, один из которых — девочка" как "мы посмотрели на одного из двух детей, и увидели девочку". Потому что если мы посмотрели на обоих и нашли девочку, то мы как бы уже всё знаем и нет смысла говорить о вероятности.
То есть неявно подразумевается, что первый ребенок - девочка. Не обязательно первый в порядке рождения, а первый, которого мы увидели.
Как вам такая формулировка: "Отец двух детей на вопрос, есть ли у него дочь, ответил - да. Какова вероятность, что у него две дочери?"
Нет. Вот в такой формулировке 1/2. Тут мы посмотрели на одного ребенка и увидели девочку. А если бы увидели мальчика, сразу исключили бы из рассмотрения. Именно из такого понимания вылезает 1/2 - мы посмотрели только на одного из детей и это девочка. Потому что если мы посмотрели на обоих, то мы уже всё знаем, какой смысл говорить о вероятности? А если посмотрели на одного и это мальчик, сразу исключили из дальнейшего рассмотрения. Ну вот такое понимание есть у людей.
Ну а как в бытовой ситуации получить эту самую 1/3, когда ваш знакомый сказал вам, что у него двое детей? Ну самое простое - спросить, а есть ли у него дочь. При положительном ответе вероятность, что дочерей две - 1/3.
После вызова перемещающего конструктора для базового класса мы не знаем, какие значения лежат в other в полях базового класса. А поля производного не изменились.
static_cast / dynamic_cast к производному классу в конструкторе? Это дичь какая-то. Конечно умышленно навредить можно. Но в реальном коде такого не может быть. Вызов виртуального метода у other? Ну тут может быть даже можно какой-нибудь искусственный пример придумать. Но в этом конкретном случае виртуальных методов нет. То есть в каких-то малореальных искусственных ситуациях при вызове
Derived(Derived&& other) : Base(std::move(other))
конструктор базового класса может изменить поля в Derived, но сам по себе вызов move ничего не портит. Это эквивалентно
Derived(Derived&& other) : Base((Base&&)other).
Почему-то я про noexcept подумал. Был не прав, согласен с вами.
Как конструктор копирования может быть exception safe, если надо выделять память?
Ну не совсем по приколу, но тут в тексте написано "Во всей стандартной библиотеке C++ эта функция, пожалуй, названа наиболее превратно."
Осмысленно использовать b затруднительно исключительно потому, что мы не знаем, какое в нем после этого лежит значение.
Как функция базового класса может что-то сделать с полем, определенном в производном классе?
Да, в случайном.
И нет, не важно стало что в базовом классе - пока в конструкторе Derived не берутся данные из базового класса.
Не move меняет состояние объекта, а конструктор.
"в неспецифицированном состоянии" - это только о том, что стандарт не оговаривает, какое значение будет. И компилятору не нужно ничего различать.
До того, как в с++ завезли rvalue ссылки, был такой auto_ptr и у него обычный оператор присваивания менял значение аргумента: после a = b; значение b занулялось - он использовал обычную lvalue ссылку. И это разрыв шаблона для программиста. А компилятору всё равно. Так вот если вы в конструкторе поменяете &&other на &other и уберете std::move, то с точки зрения компилятора код надо генерировать точно такой же. А у программиста будет некоторое недоумение по поводу неожиданного изменения параметра.
Не правда.
Нет
Не обязательно пустой. В неизвестном валидном состоянии.
Можно использовать, если нам не важно, что в нем.
Ничего не заканчивает
Никак не помечает
Объект никуда не перемещен. И компилятор ничего, кроме передачи объекта в функцию, с ним не делает. Как и любое другое приведение типа ничего само не делает с исходным объектом. Функция может делать с объектом что угодно, но оставить его в валидном состоянии. Например, после a = std::move(b); в b может оказаться значение, бывшее до присваивания в a - если поменять значения местами дешевле, чем создать пустое значение.
Но функция тут - конструктор базового класса. Она получает ссылку на базовый класс, и не может ничего сделать с полями производного класса.
Откуда взялось "компилятор помечает объект перемещенным"? Объект помечается как rvalue, что позволяет передать его в функцию, принимающую rvalue ссылку. И ничего больше.
Тут вообще-то вся статья рассказывает, что move ничего не перемещает. А конструктор по ссылке базового класса может изменить только что-то в базовом классе.
Если в конструкторе Derived (или derived_data_) пытаться обращаться к элементам базового класса, то проблема с тем, что базовый объект перемещен, конечно будет. А если не обращаться, то вроде нормально.
Динамическое трение ?
Ну блин. "Есть ли у вас дочь? Отвечайте да или нет".
Хорошая формулировка. Только ее надо к условиям задачи дописать.
Это не я придумал. Этот вариант есть в той статье в википедии, которая упоминается в начале.
"Из всех семей с двумя детьми один ребёнок выбирается случайным образом, и пол этого ребёнка сообщается (т.е. говорится либо «хотя бы один ребёнок — мальчик», либо «хотя бы один ребёнок — девочка»). В этом случае ответ 1/2"
Ну это вы считаете, что "известно, что пол одного из детей - девочка" - математически строгое утверждение. А на бытовом уровне это вполне может значить "видели гуляющим с дочерью", то есть как раз что пол случайного ребёнка - девочка. То есть пока вы не объясните, откуда известно про пол одного из детей, вопрос может быть неоднозначным.
Нет разницы. Не в том проблема. Как мы узнали, что на одной из монет орел? Пока вы этого не объясните, утверждение "известно, что на одной из монет орел" может читаться как "мы посмотрели на одну из монет, а на вторую не смотрели".
Откуда возникает парадокс - люди понимают фразу "семья с двумя детьми, один из которых — девочка" как "мы посмотрели на одного из двух детей, и увидели девочку". Потому что если мы посмотрели на обоих и нашли девочку, то мы как бы уже всё знаем и нет смысла говорить о вероятности.
То есть неявно подразумевается, что первый ребенок - девочка. Не обязательно первый в порядке рождения, а первый, которого мы увидели.
Как вам такая формулировка:
"Отец двух детей на вопрос, есть ли у него дочь, ответил - да. Какова вероятность, что у него две дочери?"
Не туда
Нет. Вот в такой формулировке 1/2. Тут мы посмотрели на одного ребенка и увидели девочку. А если бы увидели мальчика, сразу исключили бы из рассмотрения. Именно из такого понимания вылезает 1/2 - мы посмотрели только на одного из детей и это девочка. Потому что если мы посмотрели на обоих, то мы уже всё знаем, какой смысл говорить о вероятности? А если посмотрели на одного и это мальчик, сразу исключили из дальнейшего рассмотрения. Ну вот такое понимание есть у людей.
Ну а как в бытовой ситуации получить эту самую 1/3, когда ваш знакомый сказал вам, что у него двое детей? Ну самое простое - спросить, а есть ли у него дочь. При положительном ответе вероятность, что дочерей две - 1/3.
Если перекуп не продал билеты, он попал на деньги. И на следующий матч он ничего покупать не уже будет.