0

我正在尝试创建一个移动分配函数,但我不断收到“未分配指针被释放”

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 中设置断点以进行调试

4

2 回答 2

4

这个:

delete[] str;

删除str. 但是之后:

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

str被删除。所以这是未定义的行为。

反正这不是怎么做的一招。移动的重点是避免复制字符串。假设str是 a char*,那么正确的实现如下(参数的通用名称是rhs,意思是“右手边”):

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

同样:如果str只是一个指针,这只是一个正确的实现。请注意,该实现不会删除任何内容。删除将发生在rhs. 说明noexcept符不是必需的,但由于此实现永远不会抛出异常,因此标记它noexcept允许编译器进行更多优化。

于 2019-06-10T22:11:21.427 回答
0

除了Nikos C.回答

交换不是唯一的解决方案——但它是一个非常优雅的解决方案:您保留目标字符串的内存以在源字符串中重用。虽然到目前为止还不错,但您可能希望在移动后以空字符串重新开始。同样,您不应该删除内存,它非常适合重复使用。所以你只需将长度设置为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;
    }
};

但是请注意,这是可选的,实际上,您可能会让人们为他们可能不需要的东西付费——如果他们不重用从对象移动的...

于 2019-06-10T22:28:59.877 回答