You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Insertion Sort实现报错:Song对象无法赋值问题求助

问题分析与解决方案

首先,咱们来搞清楚这个错误的核心原因:你的Song类里的所有私有成员都是const修饰的(title_、artist_、callback_)。根据C++的规则,如果一个类包含const成员、引用成员,或者某个成员的拷贝赋值运算符被删除,编译器会自动删除这个类的默认拷贝赋值运算符(operator=)。而你在排序代码里写的*itr = j;和*jtr = i;,本质就是在调用这个被删除的赋值运算符,所以编译器直接抛出了错误。

下面给你两种可行的解决思路,你可以根据业务需求选择:


思路1:移除成员变量的const修饰(最简单直接)

如果你的业务逻辑允许Song对象的属性被修改,那直接把Song类里私有成员的const关键字去掉就行:

private:
    string title_;          // 移除const修饰
    string artist_;         // 移除const修饰
    function<void()> callback_; // 移除const修饰

这样编译器会自动为Song生成默认的拷贝赋值运算符,你原来的交换代码就能正常运行了。


思路2:保持Song不可变,改用链表节点操作

如果业务上要求Song对象是不可修改的(必须保留const成员),那咱们不能用赋值的方式交换元素,得直接操作std::list的节点。这里给你两种实现方式:

方式A:用std::swap交换元素

虽然Song没有拷贝赋值运算符,但只要它有拷贝构造函数(你的Song有公开构造函数,编译器会生成默认拷贝构造,且成员都支持拷贝),std::swap就能正常工作(它会通过拷贝构造创建临时对象完成交换)。同时,你原来的插入排序逻辑存在小问题,插入排序的核心是把当前元素和前一个元素依次比较,直到找到正确位置,修正后的代码如下:

// 修正后的插入排序代码
list<Song> newSongList = songs_; // 假设从原列表复制得到待排序列表
for (auto itr = next(newSongList.begin()); itr != newSongList.end(); ++itr) {
    auto jtr = itr;
    while (jtr != newSongList.begin()) {
        auto prevJtr = prev(jtr);
        cout << prevJtr->GetTitle() << " " << jtr->GetTitle() << endl;
        // 如果前一个元素不应该排在当前元素前面,就交换
        if (!Song::CompareTitle(*prevJtr, *jtr)) {
            cout << "Swap True (" << prevJtr->GetTitle() << "," << jtr->GetTitle() << " )" << endl;
            swap(*prevJtr, *jtr);
            jtr = prevJtr;
        } else {
            break; // 找到正确位置,停止向前比较
        }
    }
}

方式B:用std::list::splice移动节点(更高效)

std::list的splice方法可以直接移动节点,不需要拷贝或赋值,非常适合处理不可变对象的排序。这种方式更贴合插入排序的本质:把当前元素从链表中取出,插入到它应该在的位置:

list<Song> newSongList = songs_;
for (auto itr = next(newSongList.begin()); itr != newSongList.end();) {
    auto current = itr;
    ++itr; // 先提前移动迭代器,因为后面会移除current节点
    // 找到current应该插入的位置
    auto insertPos = newSongList.begin();
    while (insertPos != current && Song::CompareTitle(*insertPos, *current)) {
        ++insertPos;
    }
    // 如果不在正确位置,就移动节点过去
    if (insertPos != current) {
        newSongList.splice(insertPos, newSongList, current);
    }
}

这种方法不需要拷贝Song对象,效率更高,也完全避开了赋值操作的问题。


最后提醒一句:你原来的排序逻辑里用*itr和*jtr比较是不符合插入排序逻辑的,插入排序的核心是把当前元素(jtr指向的元素)和它前面的元素依次比较,直到找到合适的位置,这点要注意哦。

内容的提问来源于stack exchange,提问作者Potion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:25:38