Создавая функцию назначения перемещения, продолжайте получать «освобожденный указатель не был выделен» - PullRequest
0 голосов
/ 11 июня 2019

Я пытаюсь создать функцию назначения перемещения, но получаю сообщение «Указатель освобожден не был выделен»

const MyString& MyString::operator=(MyString&& move){
    cout<< "Move Assignment" << endl;
    if(this != &move){
        delete[] str;
        len = move.len;
        for(int i = 0; i<len;i++){
            str[i] = move.str[i];
        }
        move.str=nullptr;
        move.len = 0;
        return *this;
    }

    return *this;
}

a.out (37068,0x1000b45c0) malloc: * ошибка дляобъект 0x1001025a0: освобожденный указатель не был выделен a.out (37068,0x1000b45c0) malloc: * установить точку останова в malloc_error_break для отладки

Ответы [ 2 ]

4 голосов
/ 11 июня 2019

Это:

delete[] str;

удаляет str.Но затем:

str[i] = move.str[i];

str удаляется.Так что это неопределенное поведение.

Во всяком случае, это не то, как сделать ход.Весь смысл движения состоит в том, чтобы избежать копирования строки.Если предположить, что str является char*, то правильной реализацией будет следующее (общее имя аргумента - rhs, что означает «правая сторона»):

MyString& MyString::operator=(MyString&& rhs) noexcept
{
    std::swap(len, rhs.len);
    std::swap(str, rhs.str);
    return *this;
}

Опять: этоявляется корректной реализацией, только если str является просто указателем.Обратите внимание, что реализация ничего не удаляет.Удаление произойдет в деструкторе rhs.Спецификатор noexcept не обязателен, но, поскольку эта реализация никогда не может вызвать исключение, отметка этого noexcept допускает некоторые дополнительные оптимизации компилятором.

0 голосов
/ 11 июня 2019

Дополнение к Никос С. * ответ :

Обмен не единственное решение, но довольно элегантное: вы сохраняете память оцелевая строка для повторного использования в исходной строке.Пока что все в порядке, вы можете начать с пустой строки после перемещения.Опять же, вы не должны удалять память, она прекрасно подходит для повторного использования.Таким образом, вы просто установите длину на 0.

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

Скорее всего, нет.Таким образом, вы бы добавили немного дополнительной памяти (например, удвоение емкости, если у вас заканчивается память).Все вместе взятые:

class MyString
{
    size_t length;
    size_t capacity;
    char* data;
public:
    MyString& operator=(MyString&& other)
    {
        if(&other != this)
        {
            std::swap(data, other.data);         // as in Nikos' answer
            std::swap(capacity, other.capacity);
            length = other.length;
            other.length = 0;                    // restart with empty string
                                                 // still you have quite a bit of
                                                 // memory already reserved
        }
        return *this;
    }
};

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

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