C++排序Workout对象vector触发C2280错误该如何修复?
问题原因分析
第一个C2280错误(Workout拷贝赋值被删除)
- 根本原因:Workout类包含
const int price成员,const类型成员初始化后不可修改,编译器会默认删除类的拷贝赋值运算符operator=。即使你手动实现了placement new版本的赋值运算符,这种写法属于非常规操作,不符合C++对const成员的语义约束。排序时需要交换元素,触发赋值操作就会报错。 - 触发场景:你在order函数里创建了tmp向量拷贝workout_options,调用std::sort排序时,sort内部需要移动/交换Workout对象,触发了被删除的赋值运算符。
第二个unique_ptr版本C2280错误
- 根本原因:
std::unique_ptr是独占型智能指针,禁止拷贝构造和拷贝赋值,你写的排序lambda参数是按值传递unique_ptr<Workout> w1,会触发拷贝操作,调用了被删除的拷贝构造函数,所以报错。
修复方案
方案1:修改Workout类适配拷贝赋值(最简便)
把const成员price改成非const,只保留getPrice接口为const,对外仍然保证只读属性,同时可以使用默认的拷贝赋值运算符,不需要手动写placement new版本的赋值函数:
class Workout { public: Workout(int w_id, std::string w_name, int w_price, WorkoutType w_type); int getPrice() const; // 可以直接用默认拷贝赋值,不需要手动实现 private: int price; // 去掉const,对外只通过getPrice()访问保证只读 };
此时原来的排序代码不需要修改就可以正常运行。
方案2:排序时不修改原对象,只排序索引(不需要修改Workout类)
如果要保留price的const属性,可以不对Workout对象本身排序,而是排序其索引,同时还能避免拷贝整个Workout向量、避免你原代码中new vector未delete的内存泄漏问题,效率更高:
std::vector<int> CheapCustomer::order(const std::vector<Workout>& workout_options) { std::vector<int> v; // 创建索引数组 std::vector<int> indices(workout_options.size()); std::iota(indices.begin(), indices.end(), 0); // 按价格排序索引 std::sort(indices.begin(), indices.end(), [&](int a, int b) { return workout_options[a].getPrice() < workout_options[b].getPrice(); }); // 按排序后的索引取id for (int idx : indices) { v.push_back(workout_options[idx].getId()); } return v; }
方案3:修复unique_ptr版本的写法(和你自己的解决方案一致)
你最终的修改是正确的,核心修正了两个点:
- 排序lambda的参数改成引用传递
unique_ptr<Workout>& w1,避免拷贝unique_ptr - push_back的时候用
std::move把临时unique_ptr转为右值,触发移动构造
建议进一步优化内存管理,不要用new创建返回的vector,直接返回栈上的vector即可,避免内存泄漏:
std::vector<int> CheapCustomer::order(const std::vector<Workout>& workout_options) { std::vector<int> v; // 直接栈上创建,不需要new std::vector<std::unique_ptr<Workout>> v_unique_ptr; for (const auto& workout : workout_options) { // 用引用遍历避免拷贝Workout v_unique_ptr.push_back(std::make_unique<Workout>(workout.getId(),workout.getName(),workout.getPrice(),workout.getType())); } std::sort(v_unique_ptr.begin(), v_unique_ptr.end(), [](const std::unique_ptr<Workout>& w1, const std::unique_ptr<Workout>& w2) { return w1->getPrice() < w2->getPrice(); }); v.push_back(v_unique_ptr[0]->getId()); return v; }
内容的提问来源于stack exchange,提问作者Tal Alter
相关产品推荐
相关产品推荐

