Удаление конструктора перемещения и создание объекта из значения rvalue - PullRequest
2 голосов
/ 21 мая 2019

Я пытаюсь понять Элемент 17 из "Effective Modern C ++" о генерации специальных функций-членов, поэтому я пробовал несколько примеров и пытался рассуждать о некотором поведении. В книге написано:

.. что когда я ссылаюсь на операцию перемещения, создающую перемещение или назначающую перемещение элементу данных или базовому классу, нет никакой гарантии, что перемещение действительно будет иметь место. «Перемещение по элементам» в действительности больше похоже на запросы по перемещению по элементам, потому что типы, для которых не разрешено перемещение (т. Е. Которые не предоставляют специальной поддержки для операций перемещения, например, большинство устаревших классов C ++ 98), будут «перемещены» Через их операции копирования. ... Кроме того, операции перемещения не будут генерироваться для любого класса, который явно объявляет операцию копирования.

Приведенный ниже код выдает ошибку, если я явно удаляю конструктор перемещения, но если я этого не делаю, объект "s1" получает копию, созданную без каких-либо ошибок. Вот ссылка на wandbox с тем же кодом: ссылка на wandbox . Наверное, я не понимаю разницы между удалением конструктора перемещения и не определения его.

#include <iostream>

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
   // S(S&&) = delete;
};

S return_lvalue() {
    S ret{};
    return ret;
}

int main() {
    std::cout << "Hello world" << std::endl;
    // Error here if I delete move constructor
    S s1 = return_lvalue();
}

Ответы [ 2 ]

3 голосов
/ 21 мая 2019

Полагаю, я не понимаю разницу между удалением конструктора перемещения и его отсутствием.

Когда вы делаете

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
};

Компилятор не будетсоздать конструктор перемещения.Если вы попытаетесь переместить его, разрешение перегрузки будет найдено только S(const S&), и вы получите копию.С

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
    S(S&&) = delete;
};

Когда вы перемещаете объект типа S, разрешение перегрузки находит S(const S&) и S(S&&), но оно выбирает S(S&&), так как это лучшее совпадение.Затем он видит, что он удален, и вы получаете ошибку.

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

0 голосов
/ 21 мая 2019

Удаление специальной функции-члена не равнозначно ее объявлению.Это то же самое, что объявить его, а затем принудительно вызвать ошибку компиляции, когда вы его используете.

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

Это не имеет ничего общего с цитатой, которая говорит, что если вы do объявляете ctor хода, но не делаетене делайте никаких «движущихся вещей», и в конечном итоге ничего ценного в действительности не будет перемещено, что может противоречить ожиданиям ваших пользователей.

Я предлагаю вам оставить свой ход незамеченным.Опять же, это не то же самое, что удаление.И один не будет сгенерирован автоматически, потому что у вас есть копия ctor.

Более подробную техническую информацию вы найдете здесь:

Обратите внимание, что ваша программа компилируется в обоих случаях в режиме C ++ 17 из-за elision.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...